SelfTest.pas

File name
C:\Users\Andreas Rejbrand\Documents\Dev\AlgoSim\SelfTest.pas
Date exported
Time exported
Formatting processor
TPascalFormattingProcessor
unit SelfTest;

{ **************************************************************************** }
{ Rejbrand AlgoSim Automatic Tests                                             }
{ Copyright © 2019-2020 Andreas Rejbrand                                       }
{ https://english.rejbrand.se/                                                 }
{ **************************************************************************** }

{$DEFINE QuickTest}

interface

uses
  Windows, SysUtils, Types, Classes, Graphics, ASNum, ASKernelDefs, ASKernel,
  ASExpression, ASObjects, ASStructs, ASObjStore, ASPropMan, ASPropStores,
  ASFcnMgr, ASFcnExp, ASExecutionContext, ASFormatters, ASFunctions,
  ASTokenizer, ASParser, ASStrFcns, Generics.Defaults, Generics.Collections,
  ASColors, ASPixmap, ASSounds, UITypes;

type
  TSelfTestProgressEvent = procedure(ATotal, APerformed, ASucceeded,
    AFailed: Integer) of object;
  TSelfTestChapterEvent = procedure(AChapterNumber: Integer;
    const AChapterName: string) of object;

procedure Run(AKernel: TASKernel; AProgressEvent: TSelfTestProgressEvent = nil;
  AChapterEvent: TSelfTestChapterEvent = nil);

implementation

uses
  Math, StrUtils, DateUtils, Character, Clipbrd, MatLits, Registry, IOUtils,
  PngImage, ASMidi, SelfTestUI;

const
  TotalCount = 495194;

{$REGION 'Infrastructure'}

var
  ElapsedTime: Double;

type
  TSelfTester = class
  strict private
  type
    TTestItem = record
      Expr: string;
      Expected, Actual: string;
      constructor Create(const AExpr, AExpected, AActual: string);
      function ToString: string;
    end;
  const
    RealMatrixNames = AnsiString('ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdfghjklmnopqrstuvwxyzåä');
    ComplexMatrixNames = AnsiString('ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdfghjklmnopqrstuvwxyzåäöüë');
    CharSamples = 'GHNÖÅÉÏÔÂÑΓΒΘЧmbåñõéïγεφю75610½¼¾⅛ⅷ፹Ⅳ⑭〤⑽⒖㉑.,!?-;:()∫∅∂⌬⌨'#32#9#13#10#$A0#1#2#7#24#27#28#31;
  var
    FKernel: TASKernel;
    FTestCount,
    FSuccessCount,
    FFailCount: Integer;
    FChapterNumber: Integer;
    FFailList: TList<TTestItem>;
    FEps: TASR;
    FProgressEvent: TSelfTestProgressEvent;
    FChapterEvent: TSelfTestChapterEvent;
    FLastStatTime: UInt64;
    procedure Log(const AText: string; const AClass: string = '');
    procedure SendProgress(AForce: Boolean = False);
    procedure Chapter(const AChapterName: string);
    procedure Test(const AExpr: string; const AExpected: TAlgosimObject;
      ATestSingleLine: Boolean = False; const AExpSingleLine: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: ExceptClass;
      const AErrorMessage: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: TASI;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: TRationalNumber;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: TASR;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: TASC;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: string;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: array of TASR); overload;
    procedure Test(const AExpr: string; const AExpected: array of TASC); overload;
    procedure Test(const AExpr: string; AColCount: Integer; const AExpected: array of TASR); overload;
    procedure Test(const AExpr: string; AColCount: Integer; const AExpected: array of TASC); overload;
    procedure Test(const AExpr: string; const AExpected: TRGB;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: THSV;
      TestSL: Boolean = False; const SL: string = ''); overload;
    procedure Test(const AExpr: string; const AExpected: THSL;
      TestSL: Boolean = False; const SL: string = ''); overload;
        procedure Test(const AExpr: string; const AExpected: Boolean); overload;
    procedure Test(const AExpr: string; const AExpected: TASOSignal); overload;
    procedure Test(const AExpr: string; const AExpected: TASOSignal;
      const AErrorMessage: string); overload;
    procedure TestSL(const AExpr, AExpected: string);
    procedure TestML(const AExpr, AExpected: string);
    procedure TestDuration(const AMaxDur: Double); overload;
    procedure TestDuration(const AMinDur, AMaxDur: Double); overload;
    procedure TestExternal(const ATestName: string; AAssertion: Boolean);
    procedure TestNumFmt(const ARatValue: string; ANumberFormat: TNumberFormat;
      ANumDigits: Integer; const AExpOutput: array of string); overload;
    procedure TestNumFmt(const ARatValue: string; ANumberFormat: TNumberFormat;
      const AExpOutput: array of string); overload;
    procedure Eps(const AEpsilon: TASR = 0);
    function _ASOEq(A, B: TAlgosimObject): Boolean;
    procedure TestSeq;
    function Name(const AFirst, ALast: string): TAlgosimStructure;
    function Person(const AFirstName, ALastName, ASex: string;
      AAge: Integer): TAlgosimStructure;
    function Jane: TAlgosimStructure;
    function Mike: TAlgosimStructure;
    function John: TAlgosimStructure;
    function Sarah: TAlgosimStructure;
    function Mary: TAlgosimStructure;
    function SPerson(const AName: string; AAge: Integer;
      const ASex: string = ''): TAlgosimStructure;
    procedure TestRealMatrixQ(const AFcnName: string;
      const APositives: AnsiString);
    procedure TestRealMatrixQImplies(const ALeft, ARight: string);
    procedure TestComplexMatrixQ(const AFcnName: string;
      const APositives: AnsiString);
    procedure TestComplexMatrixQImplies(const ALeft, ARight: string);
    function LoremIpsum(AParagraphs: Integer): string;
    procedure TestCharType(const AFcnName: string; const APositives: string);
    procedure TestDefVars;
  public
    constructor Create(AKernel: TASKernel);
    procedure RunTests;
    destructor Destroy; override;
    property OnProgress: TSelfTestProgressEvent read FProgressEvent write FProgressEvent;
    property OnChapter: TSelfTestChapterEvent read FChapterEvent write FChapterEvent;
  end;

procedure Run(AKernel: TASKernel; AProgressEvent: TSelfTestProgressEvent;
  AChapterEvent: TSelfTestChapterEvent);
begin
  with TSelfTester.Create(AKernel) do
    try
      OnProgress := AProgressEvent;
      OnChapter := AChapterEvent;
      RunTests;
    finally
      Free;
    end;
end;

{ TSelfTester.TTestItem }

constructor TSelfTester.TTestItem.Create(const AExpr, AExpected,
  AActual: string);
begin
  Self.Expr := AExpr;
  Self.Expected := AExpected;
  Self.Actual := AActual;
end;

function TSelfTester.TTestItem.ToString: string;
begin
  Result :=
    '--------------------------------------------'#13#10 +
    'Test failed.'#13#10 +
    Self.Expr + #13#10 +
    '  Expected: ' + Self.Expected + #13#10 +
    '    Actual: ' + Self.Actual + #13#10 +
    '--------------------------------------------'#13#10;
end;

{ TSelfTester }

procedure TSelfTester.Chapter(const AChapterName: string);
begin
  Inc(FChapterNumber);
  if Assigned(FChapterEvent) then
    FChapterEvent(FChapterNumber, AChapterName);
end;

constructor TSelfTester.Create(AKernel: TASKernel);
begin
  FFailList := TList<TTestItem>.Create;
  FKernel := AKernel;
  FKernel.ClearAllVars;
  FKernel.LoadDefVars;
  FKernel.ClearAllBuffers;
  FKernel.ClearCommandHistory;
  FEps := -1;
end;

destructor TSelfTester.Destroy;
begin
  FFailList.Free;
  FKernel.ClearCommandHistory;
  FKernel.ClearAllBuffers;
  FKernel.ClearAllVars;
  FKernel.LoadDefVars;
  inherited;
end;

procedure TSelfTester.Eps(const AEpsilon: TASR);
begin
  FEps := AEpsilon;
end;

procedure TSelfTester.Log(const AText: string; const AClass: string);
begin
  FKernel.Perform(CLIENT_COMMAND_PRINT, 0, NativeInt(PChar(AText)),
    NativeInt(PChar(AClass)), 0);
end;

function TSelfTester.LoremIpsum(AParagraphs: Integer): string;
const
  Para =
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ' +
    'incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis ' +
    'nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' +
    'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu ' +
    'fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in ' +
    'culpa qui officia deserunt mollit anim id est laborum.';
var
  p: PChar;
  i: Integer;
const
  CRLF: string = #13#10;
begin

  if AParagraphs < 1 then
    Exit('');

  SetLength(Result, AParagraphs * Para.Length + (AParagraphs - 1) * CRLF.Length);

  p := PChar(Result);

  for i := 1 to AParagraphs do
  begin
    MoveChars(Para[1], p^, Para.Length);
    Inc(p, Para.Length);
    if i < AParagraphs then
    begin
      MoveChars(CRLF[1], p^, CRLF.Length);
      Inc(p, CRLF.Length);
    end;
  end;

end;

procedure TSelfTester.RunTests;
var
  OldSeed: Integer;
begin
  SendProgress;
  OldSeed := RandSeed;
  RandSeed := 9617237;
  try
    TestSeq;
  finally
    RandSeed := OldSeed;
  end;
  SendProgress(True);
end;

function TSelfTester.Name(const AFirst, ALast: string): TAlgosimStructure;
begin
  Result := TAlgosimStructure.CreateWithValue(
    ['first', 'last'],
    [ASO(AFirst), ASO(ALast)]
  );
end;

function TSelfTester.Person(const AFirstName, ALastName, ASex: string; AAge: Integer): TAlgosimStructure;
begin
  Result := TAlgosimStructure.CreateWithValue(
    ['name', 'sex', 'age'],
    [Name(AFirstName, ALastName), ASO(ASex), ASOInt(AAge)]
  );
end;

function TSelfTester.Jane: TAlgosimStructure;
begin
  Jane := Person('Jane', 'Smith', 'female', 40);
end;

function TSelfTester.John: TAlgosimStructure;
begin
  John := Person('John', 'Stone', 'male', 69);
end;

function TSelfTester.Mary: TAlgosimStructure;
begin
  Mary := TAlgosimStructure.CreateWithValue(
    ['mother', 'father'],
    [Jane, Mike]
  );
end;

function TSelfTester.Mike: TAlgosimStructure;
begin
  Mike := Person('Mike', 'Doe', 'male', 45);
end;

function TSelfTester.Sarah: TAlgosimStructure;
begin
  Sarah := Person('Sarah', 'Lester', 'female', 25);
end;

procedure TSelfTester.SendProgress(AForce: Boolean);
begin
  if not AForce and (GetTickCount64 - FLastStatTime < 100) then
    Exit;
  if Assigned(FProgressEvent) then
  begin
    FProgressEvent(TotalCount, FTestCount, FSuccessCount, FFailCount);
  end;
  FLastStatTime := GetTickCount64;
end;

function TSelfTester.SPerson(const AName: string;
  AAge: Integer; const ASex: string): TAlgosimStructure;
begin
  if ASex.IsEmpty then
    Result := TAlgosimStructure.CreateWithValue(
      ['name', 'age'],
      [ASO(AName), ASOInt(AAge)]
    )
  else
    Result := TAlgosimStructure.CreateWithValue(
      ['name', 'age', 'sex'],
      [ASO(AName), ASOInt(AAge), ASO(ASex)]
    )
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: array of TASR);
begin
  Test(AExpr, ASO(TRealVector.Create(AExpected)));
end;

procedure TSelfTester.Test(const AExpr, AExpected: string;
  TestSL: Boolean = False; const SL: string = '');
begin
  Test(AExpr, ASO(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TASC;
  TestSL: Boolean; const SL: string);
begin
  Test(AExpr, ASO(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TRationalNumber;
  TestSL: Boolean; const SL: string);
begin
  if TestSL then
    Test('SetNumberFormat((' + AExpr + '), "fraction")', ASORat(AExpected), TestSL, SL)
  else
    Test(AExpr, ASORat(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TASI;
  TestSL: Boolean; const SL: string);
begin
  Test(AExpr, ASOInt(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TAlgosimObject;
  ATestSingleLine: Boolean = False; const AExpSingleLine: string = '');
var
  res: TAlgosimObject;
begin
  try
    Inc(FTestCount);
    try
      res := FKernel.Evaluate(AExpr);
    except
      on E: Exception do
      begin
        Inc(FFailCount);
        FFailList.Add(TTestItem.Create(AExpr, AExpected.ClassName + '(' + AExpected.ToString + ')', E.ClassName + E.Message));
        Log(FFailList.Last.ToString, 'Error');
        Exit;
      end;
    end;
    if
      (res.ClassType = AExpected.ClassType) and
      _ASOEq(res, AExpected) and
      (not ATestSingleLine or res.GetAsSingleLineText(FKernel.FormatOptions).Equals(AExpSingleLine))
    then
      Inc(FSuccessCount)
    else
    begin
      Inc(FFailCount);
      if not (res.ClassType = AExpected.ClassType) or not _ASOEq(res, AExpected) then
      begin
        if res is TAlgosimFailure then
          FFailList.Add(TTestItem.Create(AExpr, AExpected.ClassName + '(' + AExpected.ToString + ')', res.ClassName + '(' + TAlgosimFailure(res).FailureReason + ')'))
        else
          FFailList.Add(TTestItem.Create(AExpr, AExpected.ClassName + '(' + AExpected.ToString + ')', res.ClassName + '(' + res.ToString + ')'))
      end
      else
        FFailList.Add(TTestItem.Create(AExpr, AExpSingleLine, res.GetAsSingleLineText(FKernel.FormatOptions)));
      Log(FFailList.Last.ToString, 'Error');
    end;
  finally
    FEps := -1; // noexcept
    AExpected.Free;
    SendProgress;
  end;
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: ExceptClass;
  const AErrorMessage: string);
var
  res: TAlgosimObject;
begin
  Inc(FTestCount);
  try
    res := FKernel.Evaluate(AExpr);
  except
    on E: Exception do
    begin
      if (E is AExpected) and (AErrorMessage.IsEmpty or E.Message.ToLower.Contains(AErrorMessage.ToLower)) then
        Inc(FSuccessCount)
      else
      begin
        Inc(FFailCount);
        if not (E is AExpected) then
          FFailList.Add(TTestItem.Create(AExpr, AExpected.ClassName, E.ClassName))
        else
          FFailList.Add(TTestItem.Create(AExpr, AExpected.ClassName + ': ' + AErrorMessage, E.ClassName + ': ' + E.Message));
        Log(FFailList.Last.ToString, 'Error');
      end;
      SendProgress;
      Exit;
    end;
  end;
  Inc(FFailCount);
  FFailList.Add(TTestItem.Create(AExpr, AExpected.ClassName, res.ClassName + '(' + res.ToString + ')'));
  Log(FFailList.Last.ToString, 'Error');
  SendProgress;
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TASR;
  TestSL: Boolean; const SL: string);
begin
  Test(AExpr, ASO(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: array of TASC);
begin
  Test(AExpr, ASO(TComplexVector.Create(AExpected)));
end;

procedure TSelfTester.Test(const AExpr: string; AColCount: Integer;
  const AExpected: array of TASC);
begin
  Test(AExpr, ASO(TComplexMatrix.Create(AExpected, AColCount)));
end;

procedure TSelfTester.Test(const AExpr: string; AColCount: Integer;
  const AExpected: array of TASR);
begin
  Test(AExpr, ASO(TRealMatrix.Create(AExpected, AColCount)));
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TRGB;
  TestSL: Boolean = False; const SL: string = '');
begin
  Test(AExpr, ASO(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: Boolean);
begin
  Test(AExpr, ASO(AExpected));
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TASOSignal);
begin
  Test(AExpr, ASO(AExpected));
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: TASOSignal;
  const AErrorMessage: string);
var
  res: TAlgosimObject;
begin
  Assert(AExpected = failure);
  Inc(FTestCount);
  try
    res := FKernel.Evaluate(AExpr);
  except
    on E: Exception do
    begin
      Inc(FFailCount);
      FFailList.Add(TTestItem.Create(AExpr, 'failure' + ' (' + AErrorMessage + ')', E.ClassName));
      Log(FFailList.Last.ToString, 'Error');
      SendProgress;
      Exit;
    end;
  end;
  if
    (res is TAlgosimFailure)
      and
    TAlgosimFailure(res).FailureReason.ToLower.Contains(AErrorMessage.ToLower)
  then
    Inc(FSuccessCount)
  else
  begin
    Inc(FFailCount);
    if not (res is TAlgosimFailure) then
      FFailList.Add(TTestItem.Create(AExpr, 'failure', res.ClassName + '(' + res.ToString + ')'))
    else
      FFailList.Add(TTestItem.Create(AExpr, 'failure (' + AErrorMessage + ')', TAlgosimFailure(res).FailureReason));
    Log(FFailList.Last.ToString, 'Error');
  end;
  SendProgress;
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: THSL;
  TestSL: Boolean; const SL: string);
begin
  Test(AExpr, ASO(AExpected), TestSL, SL);
end;

procedure TSelfTester.Test(const AExpr: string; const AExpected: THSV;
  TestSL: Boolean; const SL: string);
begin
  Test(AExpr, ASO(AExpected), TestSL, SL);
end;

procedure TSelfTester.TestCharType(const AFcnName, APositives: string);
var
  c: Char;
begin

  for c in CharSamples do
    Test(Format('%s("%s")', [AFcnName, c]), Pos(c, APositives) <> 0);

end;

procedure TSelfTester.TestComplexMatrixQ(const AFcnName: string;
  const APositives: AnsiString);
var
  c: AnsiChar;
  x: set of AnsiChar;
begin
  x := [];
  for c in ComplexMatrixNames do
    Include(x, c);
  for c in APositives do
  begin
    Test(Format('%s(%s)', [AFcnName, c]), True);
    Exclude(x, c);
  end;
  for c in x do
    Test(Format('%s(%s)', [AFcnName, c]), False);
end;

procedure TSelfTester.TestComplexMatrixQImplies(const ALeft, ARight: string);
var
  c: AnsiChar;
begin
  for c in ComplexMatrixNames do
    Test(Format('%s(%s) ⇒ %s(%s)', [ALeft, c, ARight, c]), True);
end;

procedure TSelfTester.TestDefVars;
begin
  Eps; Test('e', 2.7182818284590452353602874);
  Eps; Test('π', 3.1415926535897932384626433);
       Test('ℎ', 6.62607015E-34); // No blasted [epsilons] [here]! No, sir. Not one, single, bloody [epsilon]! Not one! [...] No, sir! Not one blasted, miserable ...
  Eps; Test('ℏ', 6.62607015E-34 / (2*3.1415926535897932384626433));
  Test('i', ImaginaryUnit); Test('i^2', TASC(-1));
  Test('true', True);
  Test('false', False);
  Test('otherwise', True);
  Test('∅', TAlgosimSet.Create); Test('type(∅)', 'set'); Test('#∅', 0); Test('∅ = {}', True);
  Test('¶', sLineBreak);
end;

procedure TSelfTester.TestDuration(const AMinDur, AMaxDur: Double);
begin
  Test(
    AMinDur.ToString(TFormatSettings.Invariant) +
    '≤' +
    ElapsedTime.ToString(TFormatSettings.Invariant) +
    '∧' +
    ElapsedTime.ToString(TFormatSettings.Invariant) +
    '≤' +
    AMaxDur.ToString(TFormatSettings.Invariant),
    True
  );
end;

procedure TSelfTester.TestExternal(const ATestName: string;
  AAssertion: Boolean);
begin
  if AAssertion then
    Inc(FSuccessCount)
  else
  begin
    Inc(FFailCount);
    FFailList.Add(TTestItem.Create(ATestName, 'Success', 'Failure'));
    Log(FFailList.Last.ToString, 'Error');
  end;
end;

procedure TSelfTester.TestDuration(const AMaxDur: Double);
begin
  Test(
    ElapsedTime.ToString(TFormatSettings.Invariant) +
    '≤' +
    AMaxDur.ToString(TFormatSettings.Invariant),
    True
  );
end;

procedure TSelfTester.TestSL(const AExpr, AExpected: string);
begin
  Test('AsSingleLine(' + AExpr + ')', AExpected);
end;

procedure TSelfTester.TestML(const AExpr, AExpected: string);
begin
  Test('AsMultiLine(' + AExpr + ')', AExpected);
end;

procedure TSelfTester.TestNumFmt(const ARatValue: string;
  ANumberFormat: TNumberFormat; const AExpOutput: array of string);
begin
  TestNumFmt(ARatValue, ANumberFormat, -1, AExpOutput);
end;

procedure TSelfTester.TestNumFmt(const ARatValue: string;
  ANumberFormat: TNumberFormat; ANumDigits: Integer;
  const AExpOutput: array of string);

const
  NumFmtStrs: array[TNumberFormat] of string =
    ('default', 'fraction', 'fixed', 'scientific', 'power');

type
  TPrettyExpTestMode = (petmImplicit, petmOn, petmOff);

const
  PrettyExpTestModes = [Low(TPrettyExpTestMode)..High(TPrettyExpTestMode)];

  function ApplySettings(const S: string; AImplicitDef: Boolean;
    APrettyExp: TPrettyExpTestMode; ADigitGrouping: Integer): string;
  begin
    Result := S;
    if not AImplicitDef then
      Result := Format('SetNumberFormat(%s, "%s")', [Result, NumFmtStrs[ANumberFormat]]);
    if ANumDigits <> -1 then
      Result := Format('(%s) \ %d', [Result, ANumDigits]);
    if APrettyExp <> petmImplicit then
      Result := Format('SetPrettyExp(%s, %s)', [Result, IfThen(APrettyExp = petmOn, 'true', 'false')]);
    if ADigitGrouping <> -1 then
      Result := Format('SetDigitGrouping(%s, %d)', [Result, ADigitGrouping]);
  end;

  function ForceRat(const S: string): string;
  begin
    Result := Format('ToFraction(%s)', [S]);
  end;

  function ForceReal(const S: string): string;
  begin
    Result := Format('RealNumber(%s)', [S]);
  end;

  function ForceCplx(const S: string): string;
  begin
    Result := Format('ComplexNumber(%s)', [S]);
  end;

  function Unpretty(const S: string; APETM: TPrettyExpTestMode): string;
  begin
    if APETM = petmOff then
      Result := S
        .Replace('⋅10^−', 'E−')
        .Replace('⋅10^', 'E' + IfThen(ANumberFormat = nfExponent, '+'))
    else
      Result := S;
  end;

  function DoDigGr(const S: string; ADigGr: Integer): string;

    procedure DeE(var S: string);
    var
      i: Integer;
    begin
      i := S.Length;
      while (i > 0) and (S[i] <> 'E') and (S[i] <> 'e') and (S[i] <> DOT_OPERATOR) do
        Dec(i);
      if i > 0 then
        SetLength(S, i - 1);
    end;

  var
    p: Integer;
    Sgn, IntPart, IntPartGrpd, FracPart, FracPartGrpd, Suffix: string;
    i, j: Integer;
  begin

    if ADigGr < 1 then
      Exit(S);

    p := Pos('/', S);
    if p <> 0 then
      Exit(DoDigGr(Copy(S, 1, Pred(p)), ADigGr) + '/' + DoDigGr(Copy(S, Succ(p)), ADigGr));

    if IndexStr(Copy(S, 1, 1), [MINUS_SIGN, '-', '+']) <> -1 then
      Sgn := S[1];

    p := Pos('.', S);
    IntPart := Copy(S, 1 + Sgn.Length, IfThen(p = 0, MaxInt, p - 1 - Sgn.Length));
    if p <> 0 then
      FracPart := Copy(S, Succ(p));

    DeE(IntPart);
    DeE(FracPart);

    p := Pos('E', S);
    if p = 0 then
      p := Pos('e', S);
    if p = 0 then
      p := Pos(DOT_OPERATOR, S);
    if p <> 0 then
      Suffix := Copy(S, p);

    if not IntPart.IsEmpty then
    begin
      SetLength(IntPartGrpd, IntPart.Length + Ceil(IntPart.Length / ADigGr) - 1);
      j := 0;
      for i := 1 to IntPart.Length do
      begin
        if (i <> 1) and ((IntPart.Length - i + 1) mod ADigGr = 0) then
        begin
          Inc(j);
          IntPartGrpd[j] := FIGURE_SPACE;
        end;
        Inc(j);
        IntPartGrpd[j] := IntPart[i];
      end;
      Assert(j = IntPartGrpd.Length);
    end;

    if not FracPart.IsEmpty then
    begin
      SetLength(FracPartGrpd, FracPart.Length + Ceil(FracPart.Length / ADigGr) - 1);
      j := 0;
      for i := 1 to FracPart.Length do
      begin
        if (i <> 1) and (Pred(i) mod ADigGr = 0) then
        begin
          Inc(j);
          FracPartGrpd[j] := FIGURE_SPACE;
        end;
        Inc(j);
        FracPartGrpd[j] := FracPart[i];
      end;
      Assert(j = FracPartGrpd.Length);
    end;

    Result := Sgn + IntPartGrpd + IfThen(not FracPart.IsEmpty, '.') + FracPartGrpd + Suffix;

  end;

  function NZ(const S: string): Boolean;
  var
    i: Integer;
  begin
    for i := 1 to S.Length do
      if S[i].IsInArray(['E', 'e', DOT_OPERATOR]) then
        Break
      else if CharInSet(S[i], ['1'..'9']) then
        Exit(True);
    Result := False;
  end;

const
  Sgns: array[Boolean] of string = ('', MINUS_SIGN);

var
  dummy: Int64;
  i: Integer;
  LExpOutput: array[0..3] of string;
  ImplVals: array of Boolean;
  b: Boolean;
  petm: TPrettyExpTestMode;
  neg: Boolean;
  LRatValue: string;
  DigGr: Integer;

begin

  if not (Length(AExpOutput) in [1, 2, 3, 4]) then
    raise Exception.Create('TSelfTester.TestNumFmt: Incorrect array length.');

  for i := Low(LExpOutput) to High(LExpOutput) do
    LExpOutput[i] := AExpOutput[Min(i, High(AExpOutput))]
      .Replace('E', '⋅10^')
      .Replace(HYPHEN_MINUS, MINUS_SIGN)
      .Replace(#32, FIGURE_SPACE);

  if ANumberFormat = nfDefault then
    ImplVals := [False, True]
  else
    ImplVals := [False];

  for DigGr in TArray<Integer>.Create(-1, 0, 1, 2, 3, 4, 5) do
    for neg in [False, True] do
      for petm in PrettyExpTestModes do
        for b in ImplVals do
        begin

          if neg then
            LRatValue := '-' + ARatValue
          else
            LRatValue := ARatValue;

          if TryStrToInt64(ARatValue, dummy) then
          begin
            if LExpOutput[0] <> '*' then
              TestSL(ApplySettings(LRatValue, b, petm, DigGr), Sgns[neg and NZ(LExpOutput[0])] + DoDigGr(Unpretty(LExpOutput[0], petm), DigGr));
          end
          else
            if LExpOutput[0] <> '!' then
              raise Exception.CreateFmt('TSelfTester.TestNumFmt: Cannot convert "%s" to an integer.', [LRatValue]);

          if (LExpOutput[1] <> '*') and not b then
            TestSL(ApplySettings(ForceRat(LRatValue), b, petm, DigGr), Sgns[neg and NZ(LExpOutput[1])] + DoDigGr(Unpretty(LExpOutput[1], petm), DigGr));
          if LExpOutput[2] <> '*' then
            TestSL(ApplySettings(ForceReal(LRatValue), b, petm, DigGr), Sgns[neg and NZ(LExpOutput[2])] + DoDigGr(Unpretty(LExpOutput[2], petm), DigGr));
          if LExpOutput[3] <> '*' then
            TestSL(ApplySettings(ForceCplx(LRatValue), b, petm, DigGr), Sgns[neg and NZ(LExpOutput[3])] + DoDigGr(Unpretty(LExpOutput[3], petm), DigGr));

        end;

end;

function Rat(p, q: TASI): TRationalNumber;
begin
  Result := TRationalNumber.Create(p, q);
end;

function fs(const S: string): string;
var
  i: Integer;
begin
  Result := S;
  for i := 1 to S.Length do
    if Result[i] = #32 then
      Result[i] := FIGURE_SPACE;
end;

function mm(const S: string): string;
var
  i: Integer;
begin
  Result := S;
  for i := 1 to S.Length do
    if Result[i] = '-' then
      Result[i] := MINUS_SIGN
    else if Result[i] = '*' then
      Result[i] := DOT_OPERATOR;
end;


function TSelfTester._ASOEq(A, B: TAlgosimObject): Boolean;
begin
  if FEps >= 0 then
    Result := SameASO(A, B, FEps)
  else
    Result := A.Equals(B) or ((A is TAlgosimNullObject) and (B is TAlgosimNullObject));
end;

function intset(const AInts: array of TASI): TAlgosimSet;
var
  i: TASI;
begin
  Result := TAlgosimSet.Create;
  try
    for i in AInts do
      Result.AddElement(ASOInt(i));
  except
    Result.Free;
    raise;
  end;
end;

function asoset(const AElements: array of const): TAlgosimSet;
var
  i: Integer;
begin
  Result := TAlgosimSet.Create;
  try
    for i := Low(AElements) to High(AElements) do
      case AElements[i].VType of
        vtInteger:
          Result.AddElement(ASO(AElements[i].VInteger));
        vtInt64:
          Result.AddElement(ASO(AElements[i].VInt64^));
        vtBoolean:
          Result.AddElement(ASO(AElements[i].VBoolean));
        vtExtended:
          Result.AddElement(ASO(AElements[i].VExtended^));
        vtString:
          Result.AddElement(ASO(string(AElements[i].VString^)));
        vtUnicodeString:
          Result.AddElement(ASO(UnicodeString(AElements[i].VUnicodeString)));
        vtWideChar:
          Result.AddElement(ASO(AElements[i].VWideChar));
      else
        raise Exception.Create('asoset: Unsupported variant type.');
      end;
  except
    Result.Free;
    raise;
  end;
end;

function asosetex(const AElements: array of TAlgosimObject): TAlgosimSet;
var
  i: Integer;
  LastAdded: Integer;
begin
  LastAdded := -1;
  Result := TAlgosimSet.Create;
  try
    for i := Low(AElements) to High(AElements) do
    begin
      Result.AddElement(AElements[i]);
      LastAdded := i;
    end;
  except
    Result.Free;
    for i := LastAdded + 1 to High(AElements) do
      AElements[i].Free;
    raise;
  end;
end;

function asoarr(const AElements: array of const): TAlgosimArray;
var
  i: Integer;
begin
  Result := TAlgosimArray.Create;
  try
    for i := Low(AElements) to High(AElements) do
      case AElements[i].VType of
        vtInteger:
          Result.AddElement(ASO(AElements[i].VInteger));
        vtInt64:
          Result.AddElement(ASO(AElements[i].VInt64^));
        vtBoolean:
          Result.AddElement(ASO(AElements[i].VBoolean));
        vtExtended:
          Result.AddElement(ASO(AElements[i].VExtended^));
        vtString:
          Result.AddElement(ASO(string(AElements[i].VString^)));
        vtUnicodeString:
          Result.AddElement(ASO(UnicodeString(AElements[i].VUnicodeString)));
        vtWideChar:
          Result.AddElement(ASO(AElements[i].VWideChar));
      else
        raise Exception.Create('asoarr: Unsupported variant type.');
      end;
  except
    Result.Free;
    raise;
  end;
end;

function asoarrex(const AElements: array of TAlgosimObject): TAlgosimArray;
var
  i: Integer;
  LastAdded: Integer;
begin
  LastAdded := -1;
  Result := TAlgosimArray.Create;
  try
    for i := Low(AElements) to High(AElements) do
    begin
      Result.AddElement(AElements[i]);
      LastAdded := i;
    end;
  except
    Result.Free;
    for i := LastAdded + 1 to High(AElements) do
      AElements[i].Free;
    raise;
  end;
end;

function intarr(const AInts: array of TASI): TAlgosimArray;
var
  i: TASI;
begin
  Result := TAlgosimArray.Create;
  try
    for i in AInts do
      Result.AddElement(ASOInt(i));
  except
    Result.Free;
    raise;
  end;
end;

function intarrN(const AInts: array of TASI): TAlgosimArray;
var
  i: TASI;
begin
  Result := TAlgosimArray.Create;
  try
    for i in AInts do
      if i <> -1 then
        Result.AddElement(ASOInt(i))
      else
        Result.AddElement(ASO(null))
  except
    Result.Free;
    raise;
  end;
end;

function chrarr(const AChrs: array of Char): TAlgosimArray;
var
  c: Char;
begin
  Result := TAlgosimArray.Create;
  try
    for c in AChrs do
      Result.AddElement(ASO(c));
  except
    Result.Free;
    raise;
  end;
end;

function strarr(const AStrs: array of string): TAlgosimArray;
var
  s: string;
begin
  Result := TAlgosimArray.Create;
  try
    for s in AStrs do
      Result.AddElement(ASO(s));
  except
    Result.Free;
    raise;
  end;
end;

function idx2(A, B: Int64): TAlgosimArray;
begin
  Result := intarr([A, B]);
end;

function freq(AVal, AFreq: Int64): TAlgosimArray; overload;
begin
  Result := intarr([AVal, AFreq]);
end;

function freq(AVal: TASR; AFreq: Int64): TAlgosimArray; overload;
begin
  Result := asoarr([AVal, AFreq]);
end;

function freq(AVal: TASC; AFreq: Int64): TAlgosimArray; overload;
begin
  Result := asoarrex([ASO(AVal), ASOInt(AFreq)]);
end;

function freq(const AVal: string; AFreq: Int64): TAlgosimArray; overload;
begin
  Result := asoarrex([ASO(AVal), ASOInt(AFreq)]);
end;

function freq(AVal: Boolean; AFreq: Int64): TAlgosimArray; overload;
begin
  Result := asoarrex([ASO(AVal), ASOInt(AFreq)]);
end;

function freq(AVal: TAlgosimObject; AFreq: Int64): TAlgosimArray; overload;
begin
  Result := asoarrex([AVal, ASOInt(AFreq)]);
end;

var
  _hpc1, _hpc2, _hpcf: Int64;

procedure StartStopwatch;
begin
  ElapsedTime := 0.0;
  QueryPerformanceFrequency(_hpcf);
  QueryPerformanceCounter(_hpc1);
end;

procedure StopStopwatch;
begin
  QueryPerformanceCounter(_hpc2);
  ElapsedTime := (_hpc2 - _hpc1) / _hpcf;
end;


const
  SmallPrimes: array[0..999] of Integer =
    (
      2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
      79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
      167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251,
      257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
      353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
      449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557,
      563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647,
      653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757,
      761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
      877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
      991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063,
      1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
      1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259,
      1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361,
      1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453,
      1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549,
      1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621,
      1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
      1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847,
      1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
      1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039,
      2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137,
      2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251,
      2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347,
      2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437,
      2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
      2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671,
      2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
      2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843,
      2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957,
      2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067,
      3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191,
      3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307,
      3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
      3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517,
      3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
      3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701,
      3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
      3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919,
      3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021,
      4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133,
      4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
      4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357,
      4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481,
      4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591,
      4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691,
      4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801,
      4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
      4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021,
      5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147,
      5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273,
      5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399,
      5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483,
      5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591,
      5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701,
      5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821,
      5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903,
      5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053,
      6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163,
      6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271,
      6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361,
      6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491,
      6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619,
      6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733,
      6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841,
      6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961,
      6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057,
      7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207,
      7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321,
      7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477,
      7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559,
      7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669,
      7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759,
      7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901,
      7907, 7919
    );

const
  JacobiSymbolValues: array[1..59] of array[1..30] of Integer =
    (
      (1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1, -1,  1, -1, -1,  0,  1,  1, -1,  1, -1, -1,  0,  1,  1, -1,  1, -1, -1,  0,  1,  1, -1,  1, -1, -1,  0,  1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  1,  1,  1, -1, -1, -1,  1, -1,  0,  1, -1,  1,  1,  1, -1, -1, -1,  1, -1,  0,  1, -1,  1,  1,  1, -1, -1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  1,  1, -1, -1, -1, -1,  1,  1, -1,  1,  0,  1, -1,  1,  1, -1, -1, -1, -1,  1,  1, -1,  1,  0,  1, -1,  1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  0,  1,  0,  0, -1,  1,  0,  0, -1,  0, -1, -1,  0,  1,  1,  0,  1,  0,  0, -1,  1,  0,  0, -1,  0, -1, -1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1, -1,  1, -1, -1, -1,  1,  1, -1, -1, -1,  1, -1,  1,  1,  0,  1,  1, -1,  1, -1, -1, -1,  1,  1, -1, -1, -1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1, -1,  1,  1,  1,  1, -1,  1, -1,  1, -1, -1, -1, -1,  1,  1, -1,  0,  1, -1, -1,  1,  1,  1,  1, -1,  1, -1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  0,  1,  1,  0,  0, -1,  0, -1, -1,  0, -1,  0,  0,  1,  1,  0, -1,  1,  0,  1, -1,  0,  1,  1,  0,  0, -1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  1,  1, -1,  1, -1,  1,  1, -1, -1,  1,  1, -1, -1,  1, -1,  1, -1, -1, -1, -1,  0,  1,  1,  1,  1, -1,  1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1, -1,  1,  1,  1,  1, -1,  1, -1, -1, -1,  1, -1, -1,  1, -1, -1, -1,  1, -1,  1,  1,  1,  1, -1, -1,  1,  0,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1, -1,  1,  1, -1,  1,  1,  1,  1, -1, -1, -1,  1, -1,  1, -1,  1,  1,  1, -1, -1, -1, -1,  1, -1, -1,  1, -1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  0,  1, -1,  0, -1,  1,  0, -1,  0,  0, -1, -1,  0,  1,  1,  0, -1, -1,  0,  0, -1,  0,  1, -1,  0, -1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  1,  1,  0, -1,  0, -1,  1,  0,  1,  1,  1,  0,  0,  1,  1, -1, -1,  0,  0, -1, -1, -1,  0, -1,  1,  0,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  1,  1, -1, -1,  1, -1,  1,  1,  1,  1, -1, -1, -1,  1, -1, -1, -1, -1,  1, -1, -1, -1,  1,  1,  1,  1, -1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  0,  1,  1,  0, -1,  1,  0,  1,  1,  0,  0, -1,  0,  1, -1,  0, -1,  1,  0,  1, -1,  0,  1,  0,  0, -1, -1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1, -1,  1,  1, -1, -1,  1,  1,  1, -1, -1, -1, -1, -1,  1, -1,  1, -1,  1,  1, -1,  1, -1,  1, -1, -1, -1, -1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1, -1,  1, -1,  1, -1, -1,  1,  1,  1, -1,  1,  1,  1,  1,  1, -1, -1, -1,  1, -1,  1,  1,  1, -1, -1, -1, -1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  0,  1,  0,  0, -1, -1,  0,  0,  1,  0, -1,  1,  0,  1, -1,  0,  1,  0,  0, -1, -1,  0,  0,  1,  0, -1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  1,  1, -1,  1,  1,  1,  1, -1, -1,  1, -1,  1, -1,  1,  1,  1, -1, -1,  1, -1, -1,  1,  1, -1,  1,  1, -1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  0,  1,  1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  0,  1,  1,  0, -1, -1,  0, -1,  1,  0,  1,  1,  0,  1,  0,  0,  1,  1,  0, -1,  1,  0,  1, -1,  0, -1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1, -1,  1, -1,  1,  1, -1,  1,  1,  1, -1,  1, -1,  1,  1,  1, -1, -1, -1, -1, -1, -1,  1,  1, -1, -1,  1,  1, -1),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1, -1,  1,  0, -1,  1,  1,  1,  0,  0, -1,  1,  1,  0,  1,  1,  1, -1,  0, -1,  0, -1, -1,  0,  1, -1,  1, -1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1,  1,  0,  1, -1,  0,  1,  1,  0, -1, -1,  0, -1,  1,  0,  1, -1,  0,  0, -1,  0, -1, -1,  0,  1, -1,  0,  1,  1,  0),
      (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0),
      (1, -1,  1,  1,  1, -1,  1, -1,  1, -1, -1,  1, -1, -1,  1,  1,  1, -1,  1,  1,  1,  1, -1, -1,  1,  1,  1,  1,  1, -1)
    );

  KroneckerSymbolValues: array[1..30] of array[1..30] of TASI =
  (
    (1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1),
    (1,  0, -1,  0, -1,  0,  1,  0,  1,  0, -1,  0, -1,  0,  1,  0,  1,  0, -1,  0, -1,  0,  1,  0,  1,  0, -1,  0, -1,  0),
    (1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0),
    (1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0),
    (1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0,  1, -1, -1,  1,  0),
    (1,  0,  0,  0,  1,  0,  1,  0,  0,  0,  1,  0, -1,  0,  0,  0, -1,  0, -1,  0,  0,  0, -1,  0,  1,  0,  0,  0,  1,  0),
    (1,  1, -1,  1, -1, -1,  0,  1,  1, -1,  1, -1, -1,  0,  1,  1, -1,  1, -1, -1,  0,  1,  1, -1,  1, -1, -1,  0,  1,  1),
    (1,  0, -1,  0, -1,  0,  1,  0,  1,  0, -1,  0, -1,  0,  1,  0,  1,  0, -1,  0, -1,  0,  1,  0,  1,  0, -1,  0, -1,  0),
    (1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0,  1,  1,  0),
    (1,  0,  1,  0,  0,  0, -1,  0,  1,  0, -1,  0,  1,  0,  0,  0, -1,  0, -1,  0, -1,  0, -1,  0,  0,  0,  1,  0, -1,  0),
    (1, -1,  1,  1,  1, -1, -1, -1,  1, -1,  0,  1, -1,  1,  1,  1, -1, -1, -1,  1, -1,  0,  1, -1,  1,  1,  1, -1, -1, -1),
    (1,  0,  0,  0, -1,  0,  1,  0,  0,  0, -1,  0,  1,  0,  0,  0, -1,  0,  1,  0,  0,  0, -1,  0,  1,  0,  0,  0, -1,  0),
    (1, -1,  1,  1, -1, -1, -1, -1,  1,  1, -1,  1,  0,  1, -1,  1,  1, -1, -1, -1, -1,  1,  1, -1,  1,  0,  1, -1,  1,  1),
    (1,  0,  1,  0,  1,  0,  0,  0,  1,  0, -1,  0,  1,  0,  1,  0, -1,  0,  1,  0,  0,  0,  1,  0,  1,  0,  1,  0, -1,  0),
    (1,  1,  0,  1,  0,  0, -1,  1,  0,  0, -1,  0, -1, -1,  0,  1,  1,  0,  1,  0,  0, -1,  1,  0,  0, -1,  0, -1, -1,  0),
    (1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0),
    (1,  1, -1,  1, -1, -1, -1,  1,  1, -1, -1, -1,  1, -1,  1,  1,  0,  1,  1, -1,  1, -1, -1, -1,  1,  1, -1, -1, -1,  1),
    (1,  0,  0,  0, -1,  0,  1,  0,  0,  0, -1,  0, -1,  0,  0,  0,  1,  0, -1,  0,  0,  0,  1,  0,  1,  0,  0,  0, -1,  0),
    (1, -1, -1,  1,  1,  1,  1, -1,  1, -1,  1, -1, -1, -1, -1,  1,  1, -1,  0,  1, -1, -1,  1,  1,  1,  1, -1,  1, -1,  1),
    (1,  0, -1,  0,  0,  0, -1,  0,  1,  0,  1,  0, -1,  0,  0,  0, -1,  0,  1,  0,  1,  0, -1,  0,  0,  0, -1,  0,  1,  0),
    (1, -1,  0,  1,  1,  0,  0, -1,  0, -1, -1,  0, -1,  0,  0,  1,  1,  0, -1,  1,  0,  1, -1,  0,  1,  1,  0,  0, -1,  0),
    (1,  0, -1,  0, -1,  0, -1,  0,  1,  0,  0,  0,  1,  0,  1,  0, -1,  0,  1,  0,  1,  0,  1,  0,  1,  0, -1,  0,  1,  0),
    (1,  1,  1,  1, -1,  1, -1,  1,  1, -1, -1,  1,  1, -1, -1,  1, -1,  1, -1, -1, -1, -1,  0,  1,  1,  1,  1, -1,  1, -1),
    (1,  0,  0,  0,  1,  0,  1,  0,  0,  0,  1,  0, -1,  0,  0,  0, -1,  0, -1,  0,  0,  0, -1,  0,  1,  0,  0,  0,  1,  0),
    (1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  0),
    (1,  0, -1,  0,  1,  0, -1,  0,  1,  0,  1,  0,  0,  0, -1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0, -1,  0, -1,  0),
    (1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0),
    (1,  0, -1,  0, -1,  0,  0,  0,  1,  0,  1,  0, -1,  0,  1,  0, -1,  0, -1,  0,  0,  0,  1,  0,  1,  0, -1,  0,  1,  0),
    (1, -1, -1,  1,  1,  1,  1, -1,  1, -1, -1, -1,  1, -1, -1,  1, -1, -1, -1,  1, -1,  1,  1,  1,  1, -1, -1,  1,  0,  1),
    (1,  0,  0,  0,  0,  0, -1,  0,  0,  0,  1,  0,  1,  0,  0,  0,  1,  0, -1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  0)
  );

  Totients: array[1..500] of TASI =
    (
      1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30, 16, 20, 16,
      24, 12, 36, 18, 24, 16, 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28, 58, 16, 60, 30, 36, 32,
      48, 20, 66, 32, 44, 24, 70, 24, 72, 36, 40, 36, 60, 24, 78, 32, 54, 40, 82, 24, 64, 42, 56, 40, 88, 24, 72, 44, 60, 46,
      72, 32, 96, 42, 60, 40, 100, 32, 102, 48, 48, 52, 106, 36, 108, 40, 72, 48, 112, 36, 88, 56, 72, 58, 96, 32, 110, 60,
      80, 60, 100, 36, 126, 64, 84, 48, 130, 40, 108, 66, 72, 64, 136, 44, 138, 48, 92, 70, 120, 48, 112, 72, 84, 72, 148,
      40, 150, 72, 96, 60, 120, 48, 156, 78, 104, 64, 132, 54, 162, 80, 80, 82, 166, 48, 156, 64, 108, 84, 172, 56, 120, 80,
      116, 88, 178, 48, 180, 72, 120, 88, 144, 60, 160, 92, 108, 72, 190, 64, 192, 96, 96, 84, 196, 60, 198, 80, 132, 100,
      168, 64, 160, 102, 132, 96, 180, 48, 210, 104, 140, 106, 168, 72, 180, 108, 144, 80, 192, 72, 222, 96, 120, 112, 226,
      72, 228, 88, 120, 112, 232, 72, 184, 116, 156, 96, 238, 64, 240, 110, 162, 120, 168, 80, 216, 120, 164, 100, 250, 72,
      220, 126, 128, 128, 256, 84, 216, 96, 168, 130, 262, 80, 208, 108, 176, 132, 268, 72, 270, 128, 144, 136, 200, 88, 276,
      138, 180, 96, 280, 92, 282, 140, 144, 120, 240, 96, 272, 112, 192, 144, 292, 84, 232, 144, 180, 148, 264, 80, 252, 150,
      200, 144, 240, 96, 306, 120, 204, 120, 310, 96, 312, 156, 144, 156, 316, 104, 280, 128, 212, 132, 288, 108, 240, 162,
      216, 160, 276, 80, 330, 164, 216, 166, 264, 96, 336, 156, 224, 128, 300, 108, 294, 168, 176, 172, 346, 112, 348, 120,
      216, 160, 352, 116, 280, 176, 192, 178, 358, 96, 342, 180, 220, 144, 288, 120, 366, 176, 240, 144, 312, 120, 372, 160,
      200, 184, 336, 108, 378, 144, 252, 190, 382, 128, 240, 192, 252, 192, 388, 96, 352, 168, 260, 196, 312, 120, 396, 198,
      216, 160, 400, 132, 360, 200, 216, 168, 360, 128, 408, 160, 272, 204, 348, 132, 328, 192, 276, 180, 418, 96, 420, 210,
      276, 208, 320, 140, 360, 212, 240, 168, 430, 144, 432, 180, 224, 216, 396, 144, 438, 160, 252, 192, 442, 144, 352, 222,
      296, 192, 448, 120, 400, 224, 300, 226, 288, 144, 456, 228, 288, 176, 460, 120, 462, 224, 240, 232, 466, 144, 396, 184,
      312, 232, 420, 156, 360, 192, 312, 238, 478, 128, 432, 240, 264, 220, 384, 162, 486, 240, 324, 168, 490, 160, 448, 216,
      240, 240, 420, 164, 498, 200
    );

  Radicals: array[1..78] of TASI =
    (
      1, 2, 3, 2, 5, 6, 7, 2, 3, 10, 11, 6, 13, 14, 15, 2, 17, 6, 19, 10, 21, 22, 23, 6, 5, 26, 3, 14, 29, 30, 31, 2, 33, 34,
      35, 6, 37, 38, 39, 10, 41, 42, 43, 22, 15, 46, 47, 6, 7, 10, 51, 26, 53, 6, 55, 14, 57, 58, 59, 30, 61, 62, 21, 2, 65,
      66, 67, 34, 69, 70, 71, 6, 73, 74, 15, 38, 77, 78
    );

function IntInArray(const AValue: Integer; const AArray: array of Integer): Boolean;
var
  i: Integer;
begin
  for i := Low(AArray) to High(AArray) do
    if AArray[i] = AValue then
      Exit(True);
  Result := False;
end;

function IsSmallPrime(const AValue: Integer): Boolean;
begin
  if AValue > SmallPrimes[High(SmallPrimes)] then
    raise Exception.Create('IsSmallPrime: Prime candidate not small enough.');
  Result := IntInArray(AValue, SmallPrimes);
end;

procedure TSelfTester.TestRealMatrixQ(const AFcnName: string; const APositives: AnsiString);
var
  c: AnsiChar;
  x: set of AnsiChar;
begin
  x := [];
  for c in RealMatrixNames do
    Include(x, c);
  for c in APositives do
  begin
    Test(Format('%s(%s)', [AFcnName, c]), True);
    Exclude(x, c);
  end;
  for c in x do
    Test(Format('%s(%s)', [AFcnName, c]), False);
end;

procedure TSelfTester.TestRealMatrixQImplies(const ALeft, ARight: string);
var
  c: AnsiChar;
begin
  for c in RealMatrixNames do
    Test(Format('%s(%s) ⇒ %s(%s)', [ALeft, c, ARight, c]), True);
end;

procedure AvoidDateChange;
begin
  if SecondOfTheDay(Now) > 86397 then
    Sleep(5000);
end;


{$ENDREGION}

procedure TSelfTester.TestSeq;
var
  _i, _j: Integer;
  _x: TASR;
  fn, _s, _s2: string;
  _xarr, _yarr: TArray<TASR>;
  _cxarr, _cyarr: TArray<TASC>;
  _sxarr, _syarr: TArray<string>;
  _st: TStructType;
  _bin: TArray<Byte>;
  _bm: TBitmap;
  _png: TPngImage;
label
  Bookmark;
begin

  Test('SaveHistory(false)', null);

//  goto Bookmark;

  //
  //
  //  CHAPTER 1
  //  Literals and basic output formatting. Member access by value.
  //
  //

  Chapter('Literals, output formatting, member access by value');

  //
  // Integers
  //

  Test('0', 0, True, '0');
  Test('1', 1, True, '1');
  Test('2', 2, True, '2');
  Test('-1', -1, True, MINUS_SIGN + '1');
  Test(HYPHEN_MINUS + '1', -1, True, MINUS_SIGN + '1');         Assert(HYPHEN_MINUS = #$2D);
  Test(MINUS_SIGN + '1', -1, True, MINUS_SIGN + '1');           Assert(MINUS_SIGN = #$2212);
  Test('123', 123, True, '123');
  Test('-123', -123, True, MINUS_SIGN + '123');
  Test('123456789', 123456789, True, '123456789');
  Test('-123456789', -123456789, True, MINUS_SIGN + '123456789');
  Test('123456789123', 123456789123, True, '123456789123');
  Test('-123456789123', -123456789123, True, MINUS_SIGN + '123456789123');
  Test('123456789123456', 123456789123456, True, '123456789123456');
  Test('-123456789123456', -123456789123456, True, MINUS_SIGN + '123456789123456');
  Test('123456789123456789', 123456789123456789, True, '123456789123456789');
  Test('-123456789123456789', -123456789123456789, True, MINUS_SIGN + '123456789123456789');

  Test('10#0', 0, True, '0');
  Test('10#1', 1, True, '1');
  Test('-10#1', -1, True, MINUS_SIGN + '1');
  Test('10#123456', 123456, True, '123456');
  Test('-10#123456', -123456, True, MINUS_SIGN + '123456');

  Test('16#0', 0, True, '0');
  Test('16#1', 1, True, '1');
  Test('16#10', 16, True, '16');
  Test('16#FF', 255, True, '255');
  Test('-16#FF', -255, True, MINUS_SIGN + '255');
  Test('-16#ff', -255, True, MINUS_SIGN + '255');
  Test('-16#Ff', -255, True, MINUS_SIGN + '255');
  Test('-16#fF', -255, True, MINUS_SIGN + '255');
  Test('16#FFFFFFFF', 4294967295, True, '4294967295');
  Test('16#FFFFFFFFFFFFFFF', 1152921504606846975, True, '1152921504606846975');
  Test('16#fffffffffffffff', 1152921504606846975, True, '1152921504606846975');
  Test('16#20', 32, True, '32');
  Test('16#123ABCDEF', 4893429231, True, '4893429231');
  Test('16#A1B8EF81FA81FBA', 728332961084612538, True, '728332961084612538');
  Test('-16#A1B8EF81FA81FBA', -728332961084612538, True, MINUS_SIGN + '728332961084612538');
  Test('16#7FFFFFFFFFFFFFFF', 9223372036854775807, True, '9223372036854775807');
  Test('-16#7FFFFFFFFFFFFFFF', -9223372036854775807, True, MINUS_SIGN + '9223372036854775807');
  Test('16#8000000000000000', ESyntaxException, 'invalid numeric literal');

  Test('8#0', 0, True, '0');
  Test('8#1', 1, True, '1');
  Test('8#10', 8, True, '8');
  Test('8#11', 9, True, '9');
  Test('8#12', 10, True, '10');
  Test('8#15260', 6832, True, '6832');
  Test('8#4741716513576', 339557914494, True, '339557914494');
  Test('8#115651564324324455454', 1402087635523099436, True, '1402087635523099436');
  Test('-8#115651564324324455454', -1402087635523099436, True, MINUS_SIGN + '1402087635523099436');
  Test('8#777777777777777777777', 9223372036854775807, True, '9223372036854775807');
  Test('8#1000000000000000000000', ESyntaxException, 'invalid numeric literal');

  Test('2#0', 0, True, '0');
  Test('2#1', 1, True, '1');
  Test('2#10', 2, True, '2');
  Test('2#100', 4, True, '4');
  Test('2#1000', 8, True, '8');
  Test('2#10000', 16, True, '16');
  Test('2#100000', 32, True, '32');
  Test('2#1000000', 64, True, '64');
  Test('2#10000000', 128, True, '128');
  Test('2#100000000', 256, True, '256');
  Test('2#1000000000', 512, True, '512');
  Test('2#10000000000', 1024, True, '1024');
  Test('2#1000000000000000000000000', 16777216, True, '16777216');
  Test('2#100000000000000000000000000000000', 4294967296, True, '4294967296');
  Test('2#10000000000000000000000000000000000000000', 1099511627776, True, '1099511627776');
  Test('2#1011101010110110101100', 3059116, True, '3059116');
  Test('2#1001110101110100101010101010101', 1320834389, True, '1320834389');
  Test('-2#1001110101110100101010101010101', -1320834389, True, MINUS_SIGN + '1320834389');
  Test('2#101011110101010110101010101010101010101010110101010101010100110', 6317095989821483686, True, '6317095989821483686');
  Test('-2#101011110101010110101010101010101010101010110101010101010100110', -6317095989821483686, True, MINUS_SIGN + '6317095989821483686');
  Test('2#111111111111111111111111111111111111111111111111111111111111111', 9223372036854775807, True, '9223372036854775807');
  Test('2#1000000000000000000000000000000000000000000000000000000000000000', ESyntaxException, 'invalid numeric literal');

  Test('5#0', 0);
  Test('5#1', 1);
  Test('5#10', 5);
  Test('5#11', 6);
  Test('5#100', 25);
  Test('5#110', 30);
  Test('5#111', 31);
  Test('5#112', 32);
  Test('5#1000', 125);
  Test('5#123', 38);
  Test('5#1104332401304422434310311212', 9223372036854775807, True, '9223372036854775807');
  Test('5#1104332401304422434310311213', ESyntaxException, 'invalid numeric literal');

  Test('20#0', 0);
  Test('20#1', 1);
  Test('20#2', 2);
  Test('20#3', 3);
  Test('20#4', 4);
  Test('20#9', 9);
  Test('20#A', 10);
  Test('20#B', 11);
  Test('20#C', 12);
  Test('20#D', 13);
  Test('20#E', 14);
  Test('20#F', 15);
  Test('20#G', 16);
  Test('20#H', 17);
  Test('20#I', 18);
  Test('20#J', 19);
  Test('20#K', ESyntaxException, 'invalid base-20 digit "K" in numeric literal "20#K"');
  Test('20#10', 20);
  Test('20#11', 21);
  Test('20#12', 22);
  Test('20#123', 443);
  Test('20#1000', 8000);
  Test('20#a', 10);
  Test('20#b', 11);
  Test('20#c', 12);
  Test('20#5cbfjia3fh26ja7', 9223372036854775807, True, '9223372036854775807');
  Test('20#5cbfjia3fh26ja8', ESyntaxException, 'invalid numeric literal');

  Test('2#11010101010', 1706);
  Test('2#11010101020', ESyntaxException, 'invalid base-2 digit "2" in numeric literal "2#11010101020"');

  Test('10#123456', 123456);
  Test('10#12345A', ESyntaxException, 'invalid base-10 digit "A" in numeric literal "10#12345A"');

  Test('16#12345A', 1193050);
  Test('16#12345B', 1193051);
  Test('16#12345C', 1193052);
  Test('16#12345D', 1193053);
  Test('16#12345E', 1193054);
  Test('16#12345F', 1193055);
  Test('16#12345G', ESyntaxException, 'invalid base-16 digit "G" in numeric literal "16#12345G"');
  Test('16#123460', 1193056);
  Test('16#12345f', 1193055);

  Test('8#1234567', 342391);
  Test('8#1234568', ESyntaxException, 'invalid base-8 digit "8" in numeric literal "8#1234568"');
  Test('8#1234570', 342392);

  Test('36#AZ', 395);
  Test('36#ZZZZZ', 60466175);
  Test('36#az', 395);
  Test('36#zzzzz', 60466175);
  Test('36#ZzzzZ', 60466175);
  Test('36#1q7tyotd8hj0j', 8189181848448181891, True, '8189181848448181891');
  Test('-36#1q7tyotd8hj0j', -8189181848448181891, True, MINUS_SIGN + '8189181848448181891');
  Test('36#1y2p0ij32e8e7', 9223372036854775807, True, '9223372036854775807');
  Test('36#1y2p0ij32e8e8', ESyntaxException, 'invalid numeric literal');

  Test('1#156', ESyntaxException, 'invalid number base 1 in numeric literal "1#156"');
  Test('0#0', ESyntaxException, 'invalid number base 0 in numeric literal "0#0"');
  Test('37#123', ESyntaxException, 'invalid number base 37 in numeric literal "37#123"');
  Test('16#katt', ESyntaxException, 'invalid base-16 digit "k" in numeric literal "16#katt"');

  Test('36#0', 0, True, '0');
  Test('36#1', 1, True, '1');
  Test('36#2', 2, True, '2');
  Test('36#3', 3);
  Test('36#4', 4);
  Test('36#5', 5);
  Test('36#6', 6);
  Test('36#7', 7);
  Test('36#8', 8);
  Test('36#9', 9);
  Test('36#A', 10);
  Test('36#B', 11);
  Test('36#C', 12);
  Test('36#D', 13, True, '13');
  Test('36#E', 14);
  Test('36#F', 15);
  Test('36#G', 16);
  Test('36#H', 17);
  Test('36#I', 18);
  Test('36#J', 19);
  Test('36#K', 20);
  Test('36#L', 21);
  Test('36#M', 22);
  Test('36#N', 23);
  Test('36#O', 24, True, '24');
  Test('36#P', 25);
  Test('36#Q', 26);
  Test('36#R', 27);
  Test('36#S', 28);
  Test('36#T', 29);
  Test('36#U', 30);
  Test('36#V', 31);
  Test('36#W', 32);
  Test('36#X', 33);
  Test('36#Y', 34);
  Test('36#Z', 35, True, '35');
  Test('36#10', 36, True, '36');
  Test('36#11', 37, True, '37');

  Test('16#abc', 2748);
  Test('16#abc#2', ESyntaxException, 'invalid numeric literal "16#abc#2"');
  Test('1#2#3', ESyntaxException, 'invalid numeric literal "1#2#3"');

  // Format: number base

  Test('255', 255, True, '255');
  Test('SetNumberBase(255, 10)', 255, True, '255');
  Test('SetNumberBase(255, 16)', 255, True, 'FF');
  Test('SetNumberBase(255, 2)', 255, True, '11111111');
  Test('SetNumberBase(255, 3)', 255, True, '100110');
  Test('SetNumberBase(30, 30)', 30, True, '10');
  Test('SetNumberBase(36, 36)', 36, True, '10');
  Test('SetNumberBase(2#11111111, 2)', 255, True, '11111111');
  Test('SetNumberBase(2#11111111, 16)', 255, True, 'FF');

  Test('SetNumberBase(255, 1)', failure, 'Invalid number base 1.');
  Test('SetNumberBase(255, 37)', failure, 'Invalid number base 37.');
  Test('SetNumberBase(255, 999)', failure, 'Invalid number base 999.');
  Test('SetNumberBase(255, 0)', 255, True, '255');
  Test('SetNumberBase(255, -1)', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.');
  Test('SetNumberBase(255, 2.2)', failure, 'An object of type integer was expected as argument 2, but an object of type real number was given.');
  Test('SetNumberBase(255, "t")', failure, 'An object of type integer was expected as argument 2, but an object of type string was given.');
  Test('SetNumberBase(255, 16, 5)', failure, 'Too many arguments.');
  Test('SetNumberBase(255)', failure, 'Too few arguments. A required argument of type integer is missing.');

  Test('-0', 0, True, '0');
  Test('-255', -255, True, MINUS_SIGN + '255');
  Test('SetNumberBase(-255, 0)', -255, True, MINUS_SIGN + '255');
  Test('SetNumberBase(-255, 10)', -255, True, MINUS_SIGN + '255');
  Test('SetNumberBase(-255, 16)', -255, True, MINUS_SIGN + 'FF');
  Test('SetNumberBase(-255, 2)', -255, True, MINUS_SIGN + '11111111');
  Test('SetNumberBase(-255, 3)', -255, True, MINUS_SIGN + '100110');
  Test('SetNumberBase(-30, 30)', -30, True, MINUS_SIGN + '10');
  Test('SetNumberBase(-36, 36)', -36, True, MINUS_SIGN + '10');
  Test('SetNumberBase(-2#11111111, 2)', -255, True, MINUS_SIGN + '11111111');
  Test('SetNumberBase(-2#11111111, 16)', -255, True, MINUS_SIGN + 'FF');

  Test('SetNumberBase(123456789123456, 0)', 123456789123456, True, '123456789123456');
  Test('SetNumberBase(123456789123456, 10)', 123456789123456, True, '123456789123456');
  Test('SetNumberBase(123456789123456, 16)', 123456789123456, True, '7048860F9180');
  Test('SetNumberBase(123456789123456, 8)', 123456789123456, True, '3404420603710600');
  Test('SetNumberBase(123456789123456, 2)', 123456789123456, True, '11100000100100010000110000011111001000110000000');
  Test('SetNumberBase(123456789123456, 3)', 123456789123456, True, '121012010100112220101001120010');
  Test('SetNumberBase(123456789123456, 32)', 123456789123456, True, '3G9230V4C0');
  Test('SetNumberBase(123456789123456, 36)', 123456789123456, True, '17RF9KOMTC');

  Test('SetNumberBase(-123456789123456, 0)', -123456789123456, True, MINUS_SIGN + '123456789123456');
  Test('SetNumberBase(-123456789123456, 10)', -123456789123456, True, MINUS_SIGN + '123456789123456');
  Test('SetNumberBase(-123456789123456, 16)', -123456789123456, True, MINUS_SIGN + '7048860F9180');
  Test('SetNumberBase(-123456789123456, 8)', -123456789123456, True, MINUS_SIGN + '3404420603710600');
  Test('SetNumberBase(-123456789123456, 2)', -123456789123456, True, MINUS_SIGN + '11100000100100010000110000011111001000110000000');
  Test('SetNumberBase(-123456789123456, 3)', -123456789123456, True, MINUS_SIGN + '121012010100112220101001120010');
  Test('SetNumberBase(-123456789123456, 32)', -123456789123456, True, MINUS_SIGN + '3G9230V4C0');
  Test('SetNumberBase(-123456789123456, 36)', -123456789123456, True, MINUS_SIGN + '17RF9KOMTC');

  Test('SetNumberBase(123456789123456789, 0)', 123456789123456789, True, '123456789123456789');
  Test('SetNumberBase(123456789123456789, 10)', 123456789123456789, True, '123456789123456789');
  Test('SetNumberBase(123456789123456789, 16)', 123456789123456789, True, '1B69B4BACD05F15');
  Test('SetNumberBase(123456789123456789, 8)', 123456789123456789, True, '6664664565464057425');
  Test('SetNumberBase(123456789123456789, 2)', 123456789123456789, True, '110110110100110110100101110101100110100000101111100010101');
  Test('SetNumberBase(123456789123456789, 3)', 123456789123456789, True, '211012121210012202221200111210202100');
  Test('SetNumberBase(8482137697523097365, 2)', 8482137697523097365, True, '111010110110110100110110100101110101100110100000101111100010101');

  Test('SetNumberBase(-123456789123456789, 0)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetNumberBase(-123456789123456789, 10)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetNumberBase(-123456789123456789, 16)', -123456789123456789, True, MINUS_SIGN + '1B69B4BACD05F15');
  Test('SetNumberBase(-123456789123456789, 8)', -123456789123456789, True, MINUS_SIGN + '6664664565464057425');
  Test('SetNumberBase(-123456789123456789, 2)', -123456789123456789, True, MINUS_SIGN + '110110110100110110100101110101100110100000101111100010101');
  Test('SetNumberBase(-123456789123456789, 3)', -123456789123456789, True, MINUS_SIGN + '211012121210012202221200111210202100');
  Test('SetNumberBase(-8482137697523097365, 2)', -8482137697523097365, True, MINUS_SIGN + '111010110110110100110110100101110101100110100000101111100010101');

  Test('SetNumberBase(0, 0)', 0, True, '0');
  Test('SetNumberBase(0, 2)', 0, True, '0');
  Test('SetNumberBase(0, 5)', 0, True, '0');
  Test('SetNumberBase(0, 8)', 0, True, '0');
  Test('SetNumberBase(0, 10)', 0, True, '0');
  Test('SetNumberBase(0, 16)', 0, True, '0');
  Test('SetNumberBase(0, 36)', 0, True, '0');

  Test('SetNumberBase(1, 0)', 1, True, '1');
  Test('SetNumberBase(1, 2)', 1, True, '1');
  Test('SetNumberBase(1, 5)', 1, True, '1');
  Test('SetNumberBase(1, 8)', 1, True, '1');
  Test('SetNumberBase(1, 10)', 1, True, '1');
  Test('SetNumberBase(1, 16)', 1, True, '1');
  Test('SetNumberBase(1, 36)', 1, True, '1');

  Test('SetNumberBase(2, 0)', 2, True, '2');
  Test('SetNumberBase(2, 2)', 2, True, '10');
  Test('SetNumberBase(2, 5)', 2, True, '2');
  Test('SetNumberBase(2, 8)', 2, True, '2');
  Test('SetNumberBase(2, 10)', 2, True, '2');
  Test('SetNumberBase(2, 16)', 2, True, '2');
  Test('SetNumberBase(2, 36)', 2, True, '2');

  Test('SetNumberBase(-2, 0)', -2, True, MINUS_SIGN + '2');
  Test('SetNumberBase(-2, 2)', -2, True, MINUS_SIGN + '10');
  Test('SetNumberBase(-2, 5)', -2, True, MINUS_SIGN + '2');
  Test('SetNumberBase(-2, 8)', -2, True, MINUS_SIGN + '2');
  Test('SetNumberBase(-2, 10)', -2, True, MINUS_SIGN + '2');
  Test('SetNumberBase(-2, 16)', -2, True, MINUS_SIGN + '2');
  Test('SetNumberBase(-2, 36)', -2, True, MINUS_SIGN + '2');

  Test('SetNumberBase(2, 2)', 2, True, '10');
  Test('SetNumberBase(3, 3)', 3, True, '10');
  Test('SetNumberBase(4, 4)', 4, True, '10');
  Test('SetNumberBase(5, 5)', 5, True, '10');
  Test('SetNumberBase(6, 6)', 6, True, '10');
  Test('SetNumberBase(7, 7)', 7, True, '10');
  Test('SetNumberBase(8, 8)', 8, True, '10');
  Test('SetNumberBase(9, 9)', 9, True, '10');
  Test('SetNumberBase(10, 10)', 10, True, '10');
  Test('SetNumberBase(11, 11)', 11, True, '10');

  Test('SetNumberBase(0, 36)', 0, True, '0');
  Test('SetNumberBase(1, 36)', 1, True, '1');
  Test('SetNumberBase(2, 36)', 2, True, '2');
  Test('SetNumberBase(3, 36)', 3, True, '3');
  Test('SetNumberBase(4, 36)', 4, True, '4');
  Test('SetNumberBase(5, 36)', 5, True, '5');
  Test('SetNumberBase(6, 36)', 6, True, '6');
  Test('SetNumberBase(7, 36)', 7, True, '7');
  Test('SetNumberBase(8, 36)', 8, True, '8');
  Test('SetNumberBase(9, 36)', 9, True, '9');
  Test('SetNumberBase(10, 36)', 10, True, 'A');
  Test('SetNumberBase(11, 36)', 11, True, 'B');
  Test('SetNumberBase(12, 36)', 12, True, 'C');
  Test('SetNumberBase(13, 36)', 13, True, 'D');
  Test('SetNumberBase(14, 36)', 14, True, 'E');
  Test('SetNumberBase(15, 36)', 15, True, 'F');
  Test('SetNumberBase(16, 36)', 16, True, 'G');
  Test('SetNumberBase(17, 36)', 17, True, 'H');
  Test('SetNumberBase(18, 36)', 18, True, 'I');
  Test('SetNumberBase(19, 36)', 19, True, 'J');
  Test('SetNumberBase(20, 36)', 20, True, 'K');
  Test('SetNumberBase(21, 36)', 21, True, 'L');
  Test('SetNumberBase(22, 36)', 22, True, 'M');
  Test('SetNumberBase(23, 36)', 23, True, 'N');
  Test('SetNumberBase(24, 36)', 24, True, 'O');
  Test('SetNumberBase(25, 36)', 25, True, 'P');
  Test('SetNumberBase(26, 36)', 26, True, 'Q');
  Test('SetNumberBase(27, 36)', 27, True, 'R');
  Test('SetNumberBase(28, 36)', 28, True, 'S');
  Test('SetNumberBase(29, 36)', 29, True, 'T');
  Test('SetNumberBase(30, 36)', 30, True, 'U');
  Test('SetNumberBase(31, 36)', 31, True, 'V');
  Test('SetNumberBase(32, 36)', 32, True, 'W');
  Test('SetNumberBase(33, 36)', 33, True, 'X');
  Test('SetNumberBase(34, 36)', 34, True, 'Y');
  Test('SetNumberBase(35, 36)', 35, True, 'Z');
  Test('SetNumberBase(36, 36)', 36, True, '10');
  Test('SetNumberBase(37, 36)', 37, True, '11');

  Test('SetNumberBase(856324759261834725, 2)', 856324759261834725, True, '101111100010010001101101010011100000001011000110110111100101');
  Test('SetNumberBase(856324759261834725, 3)', 856324759261834725, True, '12201001010002100111010102020021220020');
  Test('SetNumberBase(856324759261834725, 4)', 856324759261834725, True, '233202101231103200023012313211');
  Test('SetNumberBase(856324759261834725, 5)', 856324759261834725, True, '24140410144323432012202400');
  Test('SetNumberBase(856324759261834725, 6)', 856324759261834725, True, '103011414431331422425353');
  Test('SetNumberBase(856324759261834725, 7)', 856324759261834725, True, '1350602331133464501312');
  Test('SetNumberBase(856324759261834725, 8)', 856324759261834725, True, '57422155234013066745');
  Test('SetNumberBase(856324759261834725, 16)', 856324759261834725, True, 'BE246D4E02C6DE5');
  Test('SetNumberBase(856324759261834725, 32)', 856324759261834725, True, 'NOI6QJG2ORF5');
  Test('SetNumberBase(856324759261834725, 36)', 856324759261834725, True, '6I7PSJLAEQXX');

  Test('SetNumberBase(-856324759261834725, 2)', -856324759261834725, True, MINUS_SIGN + '101111100010010001101101010011100000001011000110110111100101');
  Test('SetNumberBase(-856324759261834725, 3)', -856324759261834725, True, MINUS_SIGN + '12201001010002100111010102020021220020');
  Test('SetNumberBase(-856324759261834725, 4)', -856324759261834725, True, MINUS_SIGN + '233202101231103200023012313211');
  Test('SetNumberBase(-856324759261834725, 5)', -856324759261834725, True, MINUS_SIGN + '24140410144323432012202400');
  Test('SetNumberBase(-856324759261834725, 6)', -856324759261834725, True, MINUS_SIGN + '103011414431331422425353');
  Test('SetNumberBase(-856324759261834725, 7)', -856324759261834725, True, MINUS_SIGN + '1350602331133464501312');
  Test('SetNumberBase(-856324759261834725, 8)', -856324759261834725, True, MINUS_SIGN + '57422155234013066745');
  Test('SetNumberBase(-856324759261834725, 16)', -856324759261834725, True, MINUS_SIGN + 'BE246D4E02C6DE5');
  Test('SetNumberBase(-856324759261834725, 32)', -856324759261834725, True, MINUS_SIGN + 'NOI6QJG2ORF5');
  Test('SetNumberBase(-856324759261834725, 36)', -856324759261834725, True, MINUS_SIGN + '6I7PSJLAEQXX');

  Test('SetNumberBase(9223372036854775807, 0)', 9223372036854775807, True, '9223372036854775807');
  Test('SetNumberBase(9223372036854775807, 10)', 9223372036854775807, True, '9223372036854775807');
  Test('SetNumberBase(9223372036854775807, 2)', 9223372036854775807, True, '111111111111111111111111111111111111111111111111111111111111111');
  Test('SetNumberBase(9223372036854775807, 8)', 9223372036854775807, True, '777777777777777777777');
  Test('SetNumberBase(9223372036854775807, 16)', 9223372036854775807, True, '7FFFFFFFFFFFFFFF');
  Test('SetNumberBase(9223372036854775807, 36)', 9223372036854775807, True, '1Y2P0IJ32E8E7');

  // Format: Minimum length

  Test('SetMinLength(123, 0)', 123, True, '123');
  Test('SetMinLength(123, 1)', 123, True, '123');
  Test('SetMinLength(123, 2)', 123, True, '123');
  Test('SetMinLength(123, 3)', 123, True, '123');
  Test('SetMinLength(123, 4)', 123, True, '0123');
  Test('SetMinLength(123, 5)', 123, True, '00123');
  Test('SetMinLength(123, 6)', 123, True, '000123');
  Test('SetMinLength(123, 7)', 123, True, '0000123');
  Test('SetMinLength(123, 8)', 123, True, '00000123');
  Test('SetMinLength(123, 9)', 123, True, '000000123');
  Test('SetMinLength(123, 10)', 123, True, '0000000123');
  Test('SetMinLength(123, 11)', 123, True, '00000000123');
  Test('SetMinLength(123, 12)', 123, True, '000000000123');
  Test('SetMinLength(123, 13)', 123, True, '0000000000123');
  Test('SetMinLength(123, 14)', 123, True, '00000000000123');
  Test('SetMinLength(123, 15)', 123, True, '000000000000123');
  Test('SetMinLength(123, 16)', 123, True, '0000000000000123');
  Test('SetMinLength(123, 17)', 123, True, '00000000000000123');
  Test('SetMinLength(123, 18)', 123, True, '000000000000000123');
  Test('SetMinLength(123, 19)', 123, True, '0000000000000000123');
  Test('SetMinLength(123, 20)', 123, True, '00000000000000000123');

  Test('SetMinLength(-123, 0)', -123, True, MINUS_SIGN + '123');
  Test('SetMinLength(-123, 1)', -123, True, MINUS_SIGN + '123');
  Test('SetMinLength(-123, 2)', -123, True, MINUS_SIGN + '123');
  Test('SetMinLength(-123, 3)', -123, True, MINUS_SIGN + '123');
  Test('SetMinLength(-123, 4)', -123, True, MINUS_SIGN + '0123');
  Test('SetMinLength(-123, 5)', -123, True, MINUS_SIGN + '00123');
  Test('SetMinLength(-123, 6)', -123, True, MINUS_SIGN + '000123');
  Test('SetMinLength(-123, 7)', -123, True, MINUS_SIGN + '0000123');
  Test('SetMinLength(-123, 8)', -123, True, MINUS_SIGN + '00000123');
  Test('SetMinLength(-123, 9)', -123, True, MINUS_SIGN + '000000123');
  Test('SetMinLength(-123, 10)', -123, True, MINUS_SIGN + '0000000123');
  Test('SetMinLength(-123, 11)', -123, True, MINUS_SIGN + '00000000123');
  Test('SetMinLength(-123, 12)', -123, True, MINUS_SIGN + '000000000123');
  Test('SetMinLength(-123, 13)', -123, True, MINUS_SIGN + '0000000000123');
  Test('SetMinLength(-123, 14)', -123, True, MINUS_SIGN + '00000000000123');
  Test('SetMinLength(-123, 15)', -123, True, MINUS_SIGN + '000000000000123');
  Test('SetMinLength(-123, 16)', -123, True, MINUS_SIGN + '0000000000000123');
  Test('SetMinLength(-123, 17)', -123, True, MINUS_SIGN + '00000000000000123');
  Test('SetMinLength(-123, 18)', -123, True, MINUS_SIGN + '000000000000000123');
  Test('SetMinLength(-123, 19)', -123, True, MINUS_SIGN + '0000000000000000123');
  Test('SetMinLength(-123, 20)', -123, True, MINUS_SIGN + '00000000000000000123');

  Test('SetMinLength(123, 100)', 123, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123');
  Test('SetMinLength(-123, 100)', -123, True, MINUS_SIGN + '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123');

  Test('SetMinLength(0, 0)', 0, True, '0');
  Test('SetMinLength(0, 1)', 0, True, '0');
  Test('SetMinLength(0, 2)', 0, True, '00');
  Test('SetMinLength(0, 3)', 0, True, '000');
  Test('SetMinLength(0, 4)', 0, True, '0000');
  Test('SetMinLength(0, 5)', 0, True, '00000');
  Test('SetMinLength(0, 6)', 0, True, '000000');
  Test('SetMinLength(0, 20)', 0, True, '00000000000000000000');
  Test('SetMinLength(0, 100)', 0, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');

  Test('SetMinLength(-0, 0)', 0, True, '0');
  Test('SetMinLength(-0, 1)', 0, True, '0');
  Test('SetMinLength(-0, 2)', 0, True, '00');
  Test('SetMinLength(-0, 3)', 0, True, '000');
  Test('SetMinLength(-0, 4)', 0, True, '0000');
  Test('SetMinLength(-0, 5)', 0, True, '00000');
  Test('SetMinLength(-0, 6)', 0, True, '000000');
  Test('SetMinLength(-0, 20)', 0, True, '00000000000000000000');
  Test('SetMinLength(-0, 100)', 0, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');

  Test('SetMinLength(123456789123456789, 0)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 1)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 2)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 3)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 4)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 5)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 6)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 7)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 8)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 9)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 10)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 11)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 12)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 13)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 14)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 15)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 16)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 17)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 18)', 123456789123456789, True, '123456789123456789');
  Test('SetMinLength(123456789123456789, 19)', 123456789123456789, True, '0123456789123456789');
  Test('SetMinLength(123456789123456789, 20)', 123456789123456789, True, '00123456789123456789');
  Test('SetMinLength(123456789123456789, 21)', 123456789123456789, True, '000123456789123456789');
  Test('SetMinLength(123456789123456789, 22)', 123456789123456789, True, '0000123456789123456789');
  Test('SetMinLength(123456789123456789, 100)', 123456789123456789, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000123456789123456789');

  Test('SetMinLength(-123456789123456789, 0)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 1)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 2)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 3)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 4)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 5)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 6)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 7)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 8)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 9)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 10)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 11)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 12)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 13)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 14)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 15)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 16)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 17)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 18)', -123456789123456789, True, MINUS_SIGN + '123456789123456789');
  Test('SetMinLength(-123456789123456789, 19)', -123456789123456789, True, MINUS_SIGN + '0123456789123456789');
  Test('SetMinLength(-123456789123456789, 20)', -123456789123456789, True, MINUS_SIGN + '00123456789123456789');
  Test('SetMinLength(-123456789123456789, 21)', -123456789123456789, True, MINUS_SIGN + '000123456789123456789');
  Test('SetMinLength(-123456789123456789, 22)', -123456789123456789, True, MINUS_SIGN + '0000123456789123456789');
  Test('SetMinLength(-123456789123456789, 100)', -123456789123456789, True, MINUS_SIGN + '0000000000000000000000000000000000000000000000000000000000000000000000000000000000123456789123456789');

  Test('SetMinLength(123, 255)', 123, True, StringOfChar('0', 252) + '123');
  Test('SetMinLength(123, 256)', failure, 'Invalid minimum length 256.');
  Test('SetMinLength(123, -1)', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.');
  Test('SetMinLength(123, 7.6)', failure, 'An object of type integer was expected as argument 2, but an object of type real number was given.');
  Test('SetMinLength(123, "h")', failure, 'An object of type integer was expected as argument 2, but an object of type string was given.');
  Test('SetMinLength(123, 10, 20)', failure, 'Too many arguments.');
  Test('SetMinLength(123)', failure, 'Too few arguments. A required argument of type integer is missing.');

  // Format: number base + minimum length

  Test('SetMinLength(SetNumberBase(255, 10), 0)', 255, True, '255');
  Test('SetMinLength(SetNumberBase(255, 10), 1)', 255, True, '255');
  Test('SetMinLength(SetNumberBase(255, 10), 2)', 255, True, '255');
  Test('SetMinLength(SetNumberBase(255, 10), 3)', 255, True, '255');
  Test('SetMinLength(SetNumberBase(255, 10), 4)', 255, True, '0255');
  Test('SetMinLength(SetNumberBase(255, 10), 8)', 255, True, '00000255');
  Test('SetMinLength(SetNumberBase(255, 10), 16)', 255, True, '0000000000000255');
  Test('SetMinLength(SetNumberBase(255, 10), 100)', 255, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000255');

  Test('SetMinLength(SetNumberBase(-255, 10), 0)', -255, True, MINUS_SIGN + '255');
  Test('SetMinLength(SetNumberBase(-255, 10), 1)', -255, True, MINUS_SIGN + '255');
  Test('SetMinLength(SetNumberBase(-255, 10), 2)', -255, True, MINUS_SIGN + '255');
  Test('SetMinLength(SetNumberBase(-255, 10), 3)', -255, True, MINUS_SIGN + '255');
  Test('SetMinLength(SetNumberBase(-255, 10), 4)', -255, True, MINUS_SIGN + '0255');
  Test('SetMinLength(SetNumberBase(-255, 10), 8)', -255, True, MINUS_SIGN + '00000255');
  Test('SetMinLength(SetNumberBase(-255, 10), 16)', -255, True, MINUS_SIGN + '0000000000000255');
  Test('SetMinLength(SetNumberBase(-255, 10), 100)', -255, True, MINUS_SIGN + '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000255');

  Test('SetMinLength(SetNumberBase(0, 10), 0)', 0, True, '0');
  Test('SetMinLength(SetNumberBase(0, 10), 1)', 0, True, '0');
  Test('SetMinLength(SetNumberBase(0, 10), 2)', 0, True, '00');
  Test('SetMinLength(SetNumberBase(0, 10), 8)', 0, True, '00000000');
  Test('SetMinLength(SetNumberBase(0, 10), 100)', 0, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');

  Test('SetMinLength(SetNumberBase(255, 16), 0)', 255, True, 'FF');
  Test('SetMinLength(SetNumberBase(255, 16), 1)', 255, True, 'FF');
  Test('SetMinLength(SetNumberBase(255, 16), 2)', 255, True, 'FF');
  Test('SetMinLength(SetNumberBase(255, 16), 3)', 255, True, '0FF');
  Test('SetMinLength(SetNumberBase(255, 16), 4)', 255, True, '00FF');
  Test('SetMinLength(SetNumberBase(255, 16), 8)', 255, True, '000000FF');
  Test('SetMinLength(SetNumberBase(255, 16), 16)', 255, True, '00000000000000FF');
  Test('SetMinLength(SetNumberBase(255, 16), 100)', 255, True, '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF');

  Test('SetMinLength(SetNumberBase(-255, 16), 0)', -255, True, MINUS_SIGN + 'FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 1)', -255, True, MINUS_SIGN + 'FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 2)', -255, True, MINUS_SIGN + 'FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 3)', -255, True, MINUS_SIGN + '0FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 4)', -255, True, MINUS_SIGN + '00FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 8)', -255, True, MINUS_SIGN + '000000FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 16)', -255, True, MINUS_SIGN + '00000000000000FF');
  Test('SetMinLength(SetNumberBase(-255, 16), 100)', -255, True, MINUS_SIGN + '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF');

  Test('SetMinLength(SetNumberBase(0, 16), 0)', 0, True, '0');
  Test('SetMinLength(SetNumberBase(0, 16), 1)', 0, True, '0');
  Test('SetMinLength(SetNumberBase(0, 16), 2)', 0, True, '00');
  Test('SetMinLength(SetNumberBase(0, 16), 8)', 0, True, '00000000');
  Test('SetMinLength(SetNumberBase(0, 16), 100)', 0, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');

  Test('SetMinLength(SetNumberBase(123456789123456789, 16), 0)', 123456789123456789, True, '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(123456789123456789, 16), 1)', 123456789123456789, True, '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(123456789123456789, 16), 8)', 123456789123456789, True, '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(123456789123456789, 16), 15)', 123456789123456789, True, '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(123456789123456789, 16), 16)', 123456789123456789, True, '01B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(123456789123456789, 16), 32)', 123456789123456789, True, '000000000000000001B69B4BACD05F15');

  Test('SetMinLength(SetNumberBase(-123456789123456789, 16), 0)', -123456789123456789, True, MINUS_SIGN + '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 16), 1)', -123456789123456789, True, MINUS_SIGN + '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 16), 8)', -123456789123456789, True, MINUS_SIGN + '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 16), 15)', -123456789123456789, True, MINUS_SIGN + '1B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 16), 16)', -123456789123456789, True, MINUS_SIGN + '01B69B4BACD05F15');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 16), 32)', -123456789123456789, True, MINUS_SIGN + '000000000000000001B69B4BACD05F15');

  Test('SetMinLength(SetNumberBase(255, 2), 0)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 1)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 2)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 3)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 4)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 5)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 6)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 7)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 8)', 255, True, '11111111');
  Test('SetMinLength(SetNumberBase(255, 2), 9)', 255, True, '011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 10)', 255, True, '0011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 11)', 255, True, '00011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 12)', 255, True, '000011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 13)', 255, True, '0000011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 14)', 255, True, '00000011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 15)', 255, True, '000000011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 16)', 255, True, '0000000011111111');
  Test('SetMinLength(SetNumberBase(255, 2), 32)', 255, True, '00000000000000000000000011111111');

  Test('SetMinLength(SetNumberBase(-255, 2), 0)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 1)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 2)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 3)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 4)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 5)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 6)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 7)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 8)', -255, True, MINUS_SIGN + '11111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 9)', -255, True, MINUS_SIGN + '011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 10)', -255, True, MINUS_SIGN + '0011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 11)', -255, True, MINUS_SIGN + '00011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 12)', -255, True, MINUS_SIGN + '000011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 13)', -255, True, MINUS_SIGN + '0000011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 14)', -255, True, MINUS_SIGN + '00000011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 15)', -255, True, MINUS_SIGN + '000000011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 16)', -255, True, MINUS_SIGN + '0000000011111111');
  Test('SetMinLength(SetNumberBase(-255, 2), 32)', -255, True, MINUS_SIGN + '00000000000000000000000011111111');

  Test('SetMinLength(SetNumberBase(0, 2), 0)', 0, True, '0');
  Test('SetMinLength(SetNumberBase(0, 2), 1)', 0, True, '0');
  Test('SetMinLength(SetNumberBase(0, 2), 2)', 0, True, '00');
  Test('SetMinLength(SetNumberBase(0, 2), 8)', 0, True, '00000000');
  Test('SetMinLength(SetNumberBase(0, 2), 100)', 0, True, '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');

  Test('SetMinLength(SetNumberBase(123456789123456789, 2), 0)', 123456789123456789, True, '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(123456789123456789, 2), 1)', 123456789123456789, True, '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(123456789123456789, 2), 32)', 123456789123456789, True, '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(123456789123456789, 2), 57)', 123456789123456789, True, '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(123456789123456789, 2), 64)', 123456789123456789, True, '0000000110110110100110110100101110101100110100000101111100010101');

  Test('SetMinLength(SetNumberBase(-123456789123456789, 2), 0)', -123456789123456789, True, MINUS_SIGN + '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 2), 1)', -123456789123456789, True, MINUS_SIGN + '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 2), 32)', -123456789123456789, True, MINUS_SIGN + '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 2), 57)', -123456789123456789, True, MINUS_SIGN + '110110110100110110100101110101100110100000101111100010101');
  Test('SetMinLength(SetNumberBase(-123456789123456789, 2), 64)', -123456789123456789, True, MINUS_SIGN + '0000000110110110100110110100101110101100110100000101111100010101');

  Test('SetMinLength(SetNumberBase(9223372036854775807, 36), 16)', 9223372036854775807, True, '0001Y2P0IJ32E8E7');

  Test('SetNumberBase(SetMinLength(-255, 8), 16)', -255, True, MINUS_SIGN + '000000FF');
  Test('SetNumberBase(SetMinLength(123456789123456789, 64), 2)', 123456789123456789, True, '0000000110110110100110110100101110101100110100000101111100010101');

  // Format: digit grouping

  Test('SetDigitGrouping(123456789, 3)', 123456789, True, fs('123 456 789'));

  Test('SetDigitGrouping(123456789, 0)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 1)', 123456789, True, fs('1 2 3 4 5 6 7 8 9'));
  Test('SetDigitGrouping(123456789, 2)', 123456789, True, fs('1 23 45 67 89'));
  Test('SetDigitGrouping(123456789, 3)', 123456789, True, fs('123 456 789'));
  Test('SetDigitGrouping(123456789, 4)', 123456789, True, fs('1 2345 6789'));
  Test('SetDigitGrouping(123456789, 5)', 123456789, True, fs('1234 56789'));
  Test('SetDigitGrouping(123456789, 6)', 123456789, True, fs('123 456789'));
  Test('SetDigitGrouping(123456789, 7)', 123456789, True, fs('12 3456789'));
  Test('SetDigitGrouping(123456789, 8)', 123456789, True, fs('1 23456789'));
  Test('SetDigitGrouping(123456789, 9)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 10)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 11)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 12)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 13)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 14)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 15)', 123456789, True, fs('123456789'));
  Test('SetDigitGrouping(123456789, 16)', 123456789, True, fs('123456789'));

  Test('SetDigitGrouping(-123456789, 0)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 1)', -123456789, True, MINUS_SIGN + fs('1 2 3 4 5 6 7 8 9'));
  Test('SetDigitGrouping(-123456789, 2)', -123456789, True, MINUS_SIGN + fs('1 23 45 67 89'));
  Test('SetDigitGrouping(-123456789, 3)', -123456789, True, MINUS_SIGN + fs('123 456 789'));
  Test('SetDigitGrouping(-123456789, 4)', -123456789, True, MINUS_SIGN + fs('1 2345 6789'));
  Test('SetDigitGrouping(-123456789, 5)', -123456789, True, MINUS_SIGN + fs('1234 56789'));
  Test('SetDigitGrouping(-123456789, 6)', -123456789, True, MINUS_SIGN + fs('123 456789'));
  Test('SetDigitGrouping(-123456789, 7)', -123456789, True, MINUS_SIGN + fs('12 3456789'));
  Test('SetDigitGrouping(-123456789, 8)', -123456789, True, MINUS_SIGN + fs('1 23456789'));
  Test('SetDigitGrouping(-123456789, 9)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 10)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 11)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 12)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 13)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 14)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 15)', -123456789, True, MINUS_SIGN + fs('123456789'));
  Test('SetDigitGrouping(-123456789, 16)', -123456789, True, MINUS_SIGN + fs('123456789'));

  Test('SetDigitGrouping(0, 0)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 1)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 2)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 3)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 4)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 5)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 6)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 7)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 8)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 9)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 10)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 11)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 12)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 13)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 14)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 15)', 0, True, fs('0'));
  Test('SetDigitGrouping(0, 16)', 0, True, fs('0'));

  Test('SetDigitGrouping(123456789123456789, 0)', 123456789123456789, True, fs('123456789123456789'));
  Test('SetDigitGrouping(123456789123456789, 1)', 123456789123456789, True, fs('1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9'));
  Test('SetDigitGrouping(123456789123456789, 2)', 123456789123456789, True, fs('12 34 56 78 91 23 45 67 89'));
  Test('SetDigitGrouping(123456789123456789, 3)', 123456789123456789, True, fs('123 456 789 123 456 789'));
  Test('SetDigitGrouping(123456789123456789, 4)', 123456789123456789, True, fs('12 3456 7891 2345 6789'));
  Test('SetDigitGrouping(123456789123456789, 5)', 123456789123456789, True, fs('123 45678 91234 56789'));
  Test('SetDigitGrouping(123456789123456789, 6)', 123456789123456789, True, fs('123456 789123 456789'));
  Test('SetDigitGrouping(123456789123456789, 7)', 123456789123456789, True, fs('1234 5678912 3456789'));
  Test('SetDigitGrouping(123456789123456789, 8)', 123456789123456789, True, fs('12 34567891 23456789'));
  Test('SetDigitGrouping(123456789123456789, 9)', 123456789123456789, True, fs('123456789 123456789'));
  Test('SetDigitGrouping(123456789123456789, 10)', 123456789123456789, True, fs('12345678 9123456789'));
  Test('SetDigitGrouping(123456789123456789, 12)', 123456789123456789, True, fs('123456 789123456789'));
  Test('SetDigitGrouping(123456789123456789, 16)', 123456789123456789, True, fs('12 3456789123456789'));
  Test('SetDigitGrouping(123456789123456789, 18)', 123456789123456789, True, fs('123456789123456789'));
  Test('SetDigitGrouping(123456789123456789, 19)', 123456789123456789, True, fs('123456789123456789'));
  Test('SetDigitGrouping(123456789123456789, 20)', 123456789123456789, True, fs('123456789123456789'));

  Test('SetDigitGrouping(-123456789123456789, 0)', -123456789123456789, True, MINUS_SIGN + fs('123456789123456789'));
  Test('SetDigitGrouping(-123456789123456789, 1)', -123456789123456789, True, MINUS_SIGN + fs('1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9'));
  Test('SetDigitGrouping(-123456789123456789, 2)', -123456789123456789, True, MINUS_SIGN + fs('12 34 56 78 91 23 45 67 89'));
  Test('SetDigitGrouping(-123456789123456789, 3)', -123456789123456789, True, MINUS_SIGN + fs('123 456 789 123 456 789'));
  Test('SetDigitGrouping(-123456789123456789, 4)', -123456789123456789, True, MINUS_SIGN + fs('12 3456 7891 2345 6789'));
  Test('SetDigitGrouping(-123456789123456789, 5)', -123456789123456789, True, MINUS_SIGN + fs('123 45678 91234 56789'));
  Test('SetDigitGrouping(-123456789123456789, 6)', -123456789123456789, True, MINUS_SIGN + fs('123456 789123 456789'));
  Test('SetDigitGrouping(-123456789123456789, 7)', -123456789123456789, True, MINUS_SIGN + fs('1234 5678912 3456789'));
  Test('SetDigitGrouping(-123456789123456789, 8)', -123456789123456789, True, MINUS_SIGN + fs('12 34567891 23456789'));
  Test('SetDigitGrouping(-123456789123456789, 9)', -123456789123456789, True, MINUS_SIGN + fs('123456789 123456789'));
  Test('SetDigitGrouping(-123456789123456789, 10)', -123456789123456789, True, MINUS_SIGN + fs('12345678 9123456789'));
  Test('SetDigitGrouping(-123456789123456789, 12)', -123456789123456789, True, MINUS_SIGN + fs('123456 789123456789'));
  Test('SetDigitGrouping(-123456789123456789, 16)', -123456789123456789, True, MINUS_SIGN + fs('12 3456789123456789'));
  Test('SetDigitGrouping(-123456789123456789, 18)', -123456789123456789, True, MINUS_SIGN + fs('123456789123456789'));
  Test('SetDigitGrouping(-123456789123456789, 19)', -123456789123456789, True, MINUS_SIGN + fs('123456789123456789'));
  Test('SetDigitGrouping(-123456789123456789, 20)', -123456789123456789, True, MINUS_SIGN + fs('123456789123456789'));

  Test('SetDigitGrouping(7, 0)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 1)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 2)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 3)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 4)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 5)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 6)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 7)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 8)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 9)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 10)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 11)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 12)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 13)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 14)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 15)', 7, True, fs('7'));
  Test('SetDigitGrouping(7, 16)', 7, True, fs('7'));

  Test('SetDigitGrouping(-7, 0)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 1)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 2)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 3)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 4)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 5)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 6)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 7)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 8)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 9)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 10)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 11)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 12)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 13)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 14)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 15)', -7, True, MINUS_SIGN + fs('7'));
  Test('SetDigitGrouping(-7, 16)', -7, True, MINUS_SIGN + fs('7'));

  Test('SetDigitGrouping(123456, 127)', 123456, True, fs('123456'));
  Test('SetDigitGrouping(123456, 128)', failure, 'Invalid digit grouping size 128.');
  Test('SetDigitGrouping(123456, -1)', 123456, True, fs('123456'));
  Test('SetDigitGrouping(123456, 2.2)', failure, 'An object of type integer was expected as argument 2, but an object of type real number was given.');
  Test('SetDigitGrouping(123456, "k")', failure, 'An object of type integer was expected as argument 2, but an object of type string was given.');
  Test('SetDigitGrouping(123456, 2, 2)', failure, 'Too many arguments.');
  Test('SetDigitGrouping(123456)', failure, 'Too few arguments. A required argument of type integer is missing.');

  // Format: minimum length + digit grouping

  Test('SetMinLength(SetDigitGrouping(123, 0), 0)', 123, True, fs('123'));
  Test('SetMinLength(SetDigitGrouping(123, 0), 6)', 123, True, fs('000123'));
  Test('SetMinLength(SetDigitGrouping(123, 1), 6)', 123, True, fs('0 0 0 1 2 3'));
  Test('SetMinLength(SetDigitGrouping(123, 2), 6)', 123, True, fs('00 01 23'));
  Test('SetMinLength(SetDigitGrouping(123, 3), 6)', 123, True, fs('000 123'));
  Test('SetMinLength(SetDigitGrouping(123, 4), 6)', 123, True, fs('00 0123'));
  Test('SetMinLength(SetDigitGrouping(123, 5), 6)', 123, True, fs('0 00123'));
  Test('SetMinLength(SetDigitGrouping(123, 6), 6)', 123, True, fs('000123'));
  Test('SetMinLength(SetDigitGrouping(123, 7), 6)', 123, True, fs('000123'));
  Test('SetMinLength(SetDigitGrouping(123, 4), 16)', 123, True, fs('0000 0000 0000 0123'));

  Test('SetMinLength(SetDigitGrouping(-123, 0), 0)', -123, True, MINUS_SIGN + fs('123'));
  Test('SetMinLength(SetDigitGrouping(-123, 0), 6)', -123, True, MINUS_SIGN + fs('000123'));
  Test('SetMinLength(SetDigitGrouping(-123, 1), 6)', -123, True, MINUS_SIGN + fs('0 0 0 1 2 3'));
  Test('SetMinLength(SetDigitGrouping(-123, 2), 6)', -123, True, MINUS_SIGN + fs('00 01 23'));
  Test('SetMinLength(SetDigitGrouping(-123, 3), 6)', -123, True, MINUS_SIGN + fs('000 123'));
  Test('SetMinLength(SetDigitGrouping(-123, 4), 6)', -123, True, MINUS_SIGN + fs('00 0123'));
  Test('SetMinLength(SetDigitGrouping(-123, 5), 6)', -123, True, MINUS_SIGN + fs('0 00123'));
  Test('SetMinLength(SetDigitGrouping(-123, 6), 6)', -123, True, MINUS_SIGN + fs('000123'));
  Test('SetMinLength(SetDigitGrouping(-123, 7), 6)', -123, True, MINUS_SIGN + fs('000123'));
  Test('SetMinLength(SetDigitGrouping(-123, 4), 16)', -123, True, MINUS_SIGN + fs('0000 0000 0000 0123'));

  Test('SetMinLength(SetDigitGrouping(0, 0), 0)', 0, True, fs('0'));
  Test('SetMinLength(SetDigitGrouping(0, 0), 8)', 0, True, fs('00000000'));
  Test('SetMinLength(SetDigitGrouping(0, 2), 8)', 0, True, fs('00 00 00 00'));
  Test('SetMinLength(SetDigitGrouping(0, 3), 8)', 0, True, fs('00 000 000'));
  Test('SetMinLength(SetDigitGrouping(0, 4), 8)', 0, True, fs('0000 0000'));
  Test('SetMinLength(SetDigitGrouping(0, 6), 8)', 0, True, fs('00 000000'));
  Test('SetMinLength(SetDigitGrouping(0, 7), 8)', 0, True, fs('0 0000000'));
  Test('SetMinLength(SetDigitGrouping(0, 8), 8)', 0, True, fs('00000000'));
  Test('SetMinLength(SetDigitGrouping(0, 9), 8)', 0, True, fs('00000000'));

  // Format: number base + digit grouping

  Test('SetDigitGrouping(SetNumberBase(123456, 10), 0)', 123456, True, fs('123456'));
  Test('SetDigitGrouping(SetNumberBase(123456, 10), 2)', 123456, True, fs('12 34 56'));
  Test('SetDigitGrouping(SetNumberBase(123456, 10), 3)', 123456, True, fs('123 456'));

  Test('SetDigitGrouping(SetNumberBase(-123456, 10), 0)', -123456, True, MINUS_SIGN + fs('123456'));
  Test('SetDigitGrouping(SetNumberBase(-123456, 10), 2)', -123456, True, MINUS_SIGN + fs('12 34 56'));
  Test('SetDigitGrouping(SetNumberBase(-123456, 10), 3)', -123456, True, MINUS_SIGN + fs('123 456'));

  Test('SetDigitGrouping(SetNumberBase(0, 10), 0)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 10), 2)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 10), 3)', 0, True, fs('0'));

  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 0)', 123456789123456789, True, fs('1B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 1)', 123456789123456789, True, fs('1 B 6 9 B 4 B A C D 0 5 F 1 5'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 2)', 123456789123456789, True, fs('1 B6 9B 4B AC D0 5F 15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 3)', 123456789123456789, True, fs('1B6 9B4 BAC D05 F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 4)', 123456789123456789, True, fs('1B6 9B4B ACD0 5F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 5)', 123456789123456789, True, fs('1B69B 4BACD 05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 6)', 123456789123456789, True, fs('1B6 9B4BAC D05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 7)', 123456789123456789, True, fs('1 B69B4BA CD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 8)', 123456789123456789, True, fs('1B69B4B ACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 9)', 123456789123456789, True, fs('1B69B4 BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 10)', 123456789123456789, True, fs('1B69B 4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 12)', 123456789123456789, True, fs('1B6 9B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 14)', 123456789123456789, True, fs('1 B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 15)', 123456789123456789, True, fs('1B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 16)', 123456789123456789, True, fs('1B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 16), 32)', 123456789123456789, True, fs('1B69B4BACD05F15'));

  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 0)', -123456789123456789, True, MINUS_SIGN + fs('1B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 1)', -123456789123456789, True, MINUS_SIGN + fs('1 B 6 9 B 4 B A C D 0 5 F 1 5'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 2)', -123456789123456789, True, MINUS_SIGN + fs('1 B6 9B 4B AC D0 5F 15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 3)', -123456789123456789, True, MINUS_SIGN + fs('1B6 9B4 BAC D05 F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 4)', -123456789123456789, True, MINUS_SIGN + fs('1B6 9B4B ACD0 5F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 5)', -123456789123456789, True, MINUS_SIGN + fs('1B69B 4BACD 05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 6)', -123456789123456789, True, MINUS_SIGN + fs('1B6 9B4BAC D05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 7)', -123456789123456789, True, MINUS_SIGN + fs('1 B69B4BA CD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 8)', -123456789123456789, True, MINUS_SIGN + fs('1B69B4B ACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 9)', -123456789123456789, True, MINUS_SIGN + fs('1B69B4 BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 10)', -123456789123456789, True, MINUS_SIGN + fs('1B69B 4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 12)', -123456789123456789, True, MINUS_SIGN + fs('1B6 9B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 14)', -123456789123456789, True, MINUS_SIGN + fs('1 B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 15)', -123456789123456789, True, MINUS_SIGN + fs('1B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 16)', -123456789123456789, True, MINUS_SIGN + fs('1B69B4BACD05F15'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 32)', -123456789123456789, True, MINUS_SIGN + fs('1B69B4BACD05F15'));

  Test('SetDigitGrouping(SetNumberBase(0, 16), 0)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 16), 1)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 16), 2)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 16), 3)', 0, True, fs('0'));

  Test('SetDigitGrouping(SetNumberBase(123, 2), 0)', 123, True, fs('1111011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 1)', 123, True, fs('1 1 1 1 0 1 1'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 2)', 123, True, fs('1 11 10 11'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 3)', 123, True, fs('1 111 011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 4)', 123, True, fs('111 1011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 5)', 123, True, fs('11 11011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 6)', 123, True, fs('1 111011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 7)', 123, True, fs('1111011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 8)', 123, True, fs('1111011'));
  Test('SetDigitGrouping(SetNumberBase(123, 2), 64)', 123, True, fs('1111011'));

  Test('SetDigitGrouping(SetNumberBase(-123, 2), 0)', -123, True, MINUS_SIGN + fs('1111011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 1)', -123, True, MINUS_SIGN + fs('1 1 1 1 0 1 1'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 2)', -123, True, MINUS_SIGN + fs('1 11 10 11'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 3)', -123, True, MINUS_SIGN + fs('1 111 011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 4)', -123, True, MINUS_SIGN + fs('111 1011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 5)', -123, True, MINUS_SIGN + fs('11 11011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 6)', -123, True, MINUS_SIGN + fs('1 111011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 7)', -123, True, MINUS_SIGN + fs('1111011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 8)', -123, True, MINUS_SIGN + fs('1111011'));
  Test('SetDigitGrouping(SetNumberBase(-123, 2), 64)', -123, True, MINUS_SIGN + fs('1111011'));

  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 2), 0)', 123456789123456789, True, fs('110110110100110110100101110101100110100000101111100010101'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 2), 1)', 123456789123456789, True, fs('1 1 0 1 1 0 1 1 0 1 0 0 1 1 0 1 1 0 1 0 0 1 0 1 1 1 0 1 0 1 1 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1 1 1 1 0 0 0 1 0 1 0 1'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 2), 2)', 123456789123456789, True, fs('1 10 11 01 10 10 01 10 11 01 00 10 11 10 10 11 00 11 01 00 00 01 01 11 11 00 01 01 01'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 2), 8)', 123456789123456789, True, fs('1 10110110 10011011 01001011 10101100 11010000 01011111 00010101'));
  Test('SetDigitGrouping(SetNumberBase(123456789123456789, 2), 32)', 123456789123456789, True, fs('1101101101001101101001011 10101100110100000101111100010101'));

  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 2), 0)', -123456789123456789, True, MINUS_SIGN + fs('110110110100110110100101110101100110100000101111100010101'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 2), 1)', -123456789123456789, True, MINUS_SIGN + fs('1 1 0 1 1 0 1 1 0 1 0 0 1 1 0 1 1 0 1 0 0 1 0 1 1 1 0 1 0 1 1 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1 1 1 1 0 0 0 1 0 1 0 1'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 2), 2)', -123456789123456789, True, MINUS_SIGN + fs('1 10 11 01 10 10 01 10 11 01 00 10 11 10 10 11 00 11 01 00 00 01 01 11 11 00 01 01 01'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 2), 8)', -123456789123456789, True, MINUS_SIGN + fs('1 10110110 10011011 01001011 10101100 11010000 01011111 00010101'));
  Test('SetDigitGrouping(SetNumberBase(-123456789123456789, 2), 32)', -123456789123456789, True, MINUS_SIGN + fs('1101101101001101101001011 10101100110100000101111100010101'));

  Test('SetDigitGrouping(SetNumberBase(0, 2), 0)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 2), 1)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 2), 2)', 0, True, fs('0'));
  Test('SetDigitGrouping(SetNumberBase(0, 2), 3)', 0, True, fs('0'));

  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 0)', 9223372036854775807, True, fs('1Y2P0IJ32E8E7'));
  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 1)', 9223372036854775807, True, fs('1 Y 2 P 0 I J 3 2 E 8 E 7'));
  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 2)', 9223372036854775807, True, fs('1 Y2 P0 IJ 32 E8 E7'));
  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 3)', 9223372036854775807, True, fs('1 Y2P 0IJ 32E 8E7'));
  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 4)', 9223372036854775807, True, fs('1 Y2P0 IJ32 E8E7'));
  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 8)', 9223372036854775807, True, fs('1Y2P0 IJ32E8E7'));
  Test('SetDigitGrouping(SetNumberBase(9223372036854775807, 36), 16)', 9223372036854775807, True, fs('1Y2P0IJ32E8E7'));

  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 0)', -9223372036854775807, True, MINUS_SIGN + fs('1Y2P0IJ32E8E7'));
  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 1)', -9223372036854775807, True, MINUS_SIGN + fs('1 Y 2 P 0 I J 3 2 E 8 E 7'));
  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 2)', -9223372036854775807, True, MINUS_SIGN + fs('1 Y2 P0 IJ 32 E8 E7'));
  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 3)', -9223372036854775807, True, MINUS_SIGN + fs('1 Y2P 0IJ 32E 8E7'));
  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 4)', -9223372036854775807, True, MINUS_SIGN + fs('1 Y2P0 IJ32 E8E7'));
  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 8)', -9223372036854775807, True, MINUS_SIGN + fs('1Y2P0 IJ32E8E7'));
  Test('SetDigitGrouping(SetNumberBase(-9223372036854775807, 36), 16)', -9223372036854775807, True, MINUS_SIGN + fs('1Y2P0IJ32E8E7'));

  Test('SetDigitGrouping(SetNumberBase(0, 36), 4)', 0, True, fs('0'));

  // Format: number base + digit grouping + minimum length

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456, 10), 3), 10)', 123456, True, fs('0 000 123 456'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456, 16), 2), 8)', 123456, True, fs('00 01 E2 40'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456, 2), 8), 32)', 123456, True, fs('00000000 00000001 11100010 01000000'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456, 2), 4), 32)', 123456, True, fs('0000 0000 0000 0001 1110 0010 0100 0000'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456789123456789, 10), 3), 20)', 123456789123456789, True, fs('00 123 456 789 123 456 789'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456789123456789, 16), 2), 16)', 123456789123456789, True, fs('01 B6 9B 4B AC D0 5F 15'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(123456789123456789, 2), 8), 64)', 123456789123456789, True, fs('00000001 10110110 10011011 01001011 10101100 11010000 01011111 00010101'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(9223372036854775807, 10), 3), 20)', 9223372036854775807, True, fs('09 223 372 036 854 775 807'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(9223372036854775807, 16), 2), 16)', 9223372036854775807, True, fs('7F FF FF FF FF FF FF FF'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(9223372036854775807, 2), 8), 64)', 9223372036854775807, True, fs('01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456, 10), 3), 10)', -123456, True, MINUS_SIGN + fs('0 000 123 456'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456, 16), 2), 8)', -123456, True, MINUS_SIGN + fs('00 01 E2 40'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456, 2), 8), 32)', -123456, True, MINUS_SIGN + fs('00000000 00000001 11100010 01000000'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456, 2), 4), 32)', -123456, True, MINUS_SIGN + fs('0000 0000 0000 0001 1110 0010 0100 0000'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456789123456789, 10), 3), 20)', -123456789123456789, True, MINUS_SIGN + fs('00 123 456 789 123 456 789'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456789123456789, 16), 2), 16)', -123456789123456789, True, MINUS_SIGN + fs('01 B6 9B 4B AC D0 5F 15'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-123456789123456789, 2), 8), 64)', -123456789123456789, True, MINUS_SIGN + fs('00000001 10110110 10011011 01001011 10101100 11010000 01011111 00010101'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-9223372036854775807, 10), 3), 20)', -9223372036854775807, True, MINUS_SIGN + fs('09 223 372 036 854 775 807'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-9223372036854775807, 16), 2), 16)', -9223372036854775807, True, MINUS_SIGN + fs('7F FF FF FF FF FF FF FF'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-9223372036854775807, 2), 8), 64)', -9223372036854775807, True, MINUS_SIGN + fs('01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(853624750053, 2), 8), 64)', 853624750053, True, fs('00000000 00000000 00000000 11000110 10111111 11111111 11111111 11100101'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-853624750053, 2), 8), 64)', -853624750053, True, MINUS_SIGN + fs('00000000 00000000 00000000 11000110 10111111 11111111 11111111 11100101'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(853624750053, 2), 8), 32)', 853624750053, True, fs('11000110 10111111 11111111 11111111 11100101'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(-853624750053, 2), 8), 32)', -853624750053, True, MINUS_SIGN + fs('11000110 10111111 11111111 11111111 11100101'));

  Test('SetNumberBase(SetMinLength(SetDigitGrouping(853624750053, 8), 64), 2)', 853624750053, True, fs('00000000 00000000 00000000 11000110 10111111 11111111 11111111 11100101'));
  Test('SetNumberBase(SetNumberBase(SetDigitGrouping(SetMinLength(853624750053, 64), 8), 36), 2)', 853624750053, True, fs('00000000 00000000 00000000 11000110 10111111 11111111 11111111 11100101'));
  Test('SetMinLength(SetNumberBase(SetNumberBase(SetDigitGrouping(SetMinLength(853624750053, 255), 8), 36), 2), 64)', 853624750053, True, fs('00000000 00000000 00000000 11000110 10111111 11111111 11111111 11100101'));

  Test('SetMinLength(SetDigitGrouping(SetNumberBase(0, 10), 3), 10)', 0, True, fs('0 000 000 000'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(0, 16), 2), 8)', 0, True, fs('00 00 00 00'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(0, 2), 8), 32)', 0, True, fs('00000000 00000000 00000000 00000000'));
  Test('SetMinLength(SetDigitGrouping(SetNumberBase(0, 2), 4), 32)', 0, True, fs('0000 0000 0000 0000 0000 0000 0000 0000'));


  //
  // Rational numbers (and the division operator on integers, and operators on rationals)
  //

  Test('1/2', Rat(1, 2), True, '1/2');
  Test('1/3', Rat(1, 3), True, '1/3');
  Test('1/1000000', Rat(1, 1000000), True, '1/1000000');
  Test('1237/17', Rat(1237, 17), True, '1237/17');
  Test('1237/1238', Rat(1237, 1238), True, '1237/1238');

  Test('-1/2', Rat(-1, 2), True, MINUS_SIGN + '1/2');
  Test('-1/3', Rat(-1, 3), True, MINUS_SIGN + '1/3');
  Test('-1/1000000', Rat(-1, 1000000), True, MINUS_SIGN + '1/1000000');
  Test('-1237/17', Rat(-1237, 17), True, MINUS_SIGN + '1237/17');
  Test('-1237/1238', Rat(-1237, 1238), True, MINUS_SIGN + '1237/1238');

  Test('1/1', 1, True, '1');
  Test('2/2', 1, True, '1');
  Test('987654321/987654321', 1, True, '1');
  Test('987654320/987654321', Rat(987654320, 987654321), True, '987654320/987654321');

  Test('-1/1', -1, True, MINUS_SIGN + '1');
  Test('-2/2', -1, True, MINUS_SIGN + '1');
  Test('-987654321/987654321', -1, True, MINUS_SIGN + '1');
  Test('-987654320/987654321', Rat(-987654320, 987654321), True, MINUS_SIGN + '987654320/987654321');

  Test('0/2', 0, True, '0');
  Test('0/3', 0, True, '0');
  Test('0/1000000', 0, True, '0');
  Test('0/17', 0, True, '0');
  Test('0/1238', 0, True, '0');

  Test('4/20', Rat(1, 5), True, '1/5');
  Test('40/200', Rat(1, 5), True, '1/5');
  Test('400000000/2000000000', Rat(1, 5), True, '1/5');
  Test('40000000000000/200000000000000', Rat(1, 5), True, '1/5');

  Test('-4/20', Rat(-1, 5), True, MINUS_SIGN + '1/5');
  Test('-40/200', Rat(-1, 5), True, MINUS_SIGN + '1/5');
  Test('-400000000/2000000000', Rat(-1, 5), True, MINUS_SIGN + '1/5');
  Test('-40000000000000/200000000000000', Rat(-1, 5), True, MINUS_SIGN + '1/5');

  Test('83250/47250', Rat(37, 21), True, '37/21');

  Test('1/3 + 1/4', Rat(7, 12), True, '7/12');
  Test('1/3 - 1/4', Rat(1, 12), True, '1/12');
  Test('(1/3) ⋅ (1/4)', Rat(1, 12), True, '1/12');
  Test('(7/3) ⋅ (3/4)', Rat(7, 4), True, '7/4');
  Test('(7/3) ⋅ (5/4)', Rat(35, 12), True, '35/12');
  Test('(7/3) / (3/4)', Rat(28, 9), True, '28/9');
  Test('(7/3) / (5/4)', Rat(28, 15), True, '28/15');

  Test('1/3 ⋅ 1/4', Rat(1, 12), True, '1/12');
  Test('7/3 ⋅ 3/4', Rat(7, 4), True, '7/4');
  Test('7/3 ⋅ 5/4', Rat(35, 12), True, '35/12');

  Test('(7/3) / (7/4)', Rat(4, 3), True, '4/3');
  Test('-(7/3) / (7/4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('(-7/3) / (7/4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('(7/-3) / (7/4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('(7/3) / -(7/4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('(7/3) / (-7/4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('(7/3) / (7/-4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('-(-7/-3) / -(-7/-4)', Rat(4, 3), True, '4/3');
  Test('--(-7/-3) / -(-7/-4)', Rat(-4, 3), True, MINUS_SIGN + '4/3');
  Test('-(-(-7/-3) / -(-7/-4))', Rat(-4, 3), True, MINUS_SIGN + '4/3');

  Test('0/3 + 1/4', Rat(1, 4), True, '1/4');
  Test('0 + 1/4', Rat(1, 4), True, '1/4');
  Test('(0/3) ⋅ (1/4)', Rat(0, 1), True, '0');
  Test('0 ⋅ (1/4)', Rat(0, 1), True, '0');

  Test('1/7 + 5', Rat(36, 7), True, '36/7');
  Test('1/7 - 5', Rat(-34, 7), True, MINUS_SIGN + '34/7');

  Test('5 + 1/7', Rat(36, 7), True, '36/7');
  Test('5 - 1/7', Rat(34, 7), True, '34/7');

  Test('5 ⋅ 1/7', Rat(5, 7), True, '5/7');
  Test('(5 ⋅ 1)/7', Rat(5, 7), True, '5/7');
  Test('5 ⋅ (1/7)', Rat(5, 7), True, '5/7');

  Test('123456789123456789/123456789123456', Rat(41152263041152263, 41152263041152), True, '41152263041152263/41152263041152');
  Test('-123456789123456789/123456789123456', Rat(-41152263041152263, 41152263041152), True, MINUS_SIGN + '41152263041152263/41152263041152');
  Test('123456789123456789/-123456789123456', Rat(-41152263041152263, 41152263041152), True, MINUS_SIGN + '41152263041152263/41152263041152');
  Test('-123456789123456789/--123456789123456', Rat(-41152263041152263, 41152263041152), True, MINUS_SIGN + '41152263041152263/41152263041152');
  Test('-(-(---123456789123456789/--123456789123456))', Rat(-41152263041152263, 41152263041152), True, MINUS_SIGN + '41152263041152263/41152263041152');
  Test('-(-(---123456789123456789/-(--123456789123456)))', Rat(41152263041152263, 41152263041152), True, '41152263041152263/41152263041152');

  Test('9223372036854775807/9223372036854775807', 1, True, '1');
  Test('9223372036854775806/9223372036854775807', Rat(9223372036854775806, 9223372036854775807), True, '9223372036854775806/9223372036854775807');

  Test('-9223372036854775807/9223372036854775807', -1, True, MINUS_SIGN + '1');
  Test('-9223372036854775806/9223372036854775807', Rat(-9223372036854775806, 9223372036854775807), True, MINUS_SIGN + '9223372036854775806/9223372036854775807');

  Test('1/357 + 512/879 - 12/67 + 22/17', Rat(3972039, 2336089), True, '3972039/2336089');
  Test('52/75 + 94/73 - 12/85 + 6523/51 + 152/7', Rat(32892473, 217175), True, '32892473/217175');
  Test('2/84 - 8563/1 + 5892/7 - 2/9853', Rat(-3195259013, 413826), True, MINUS_SIGN + '3195259013/413826');
  Test('532/751 + 9583/9571 - 9856/8522 + 3/7 - 89/2', Rat(-18659885062139, 428782273934), True, MINUS_SIGN + '18659885062139/428782273934');
  Test('15236/8562712 + 9/2', Rat(4818430, 1070339), True, '4818430/1070339');
  Test('21/5784632 - 8/3', Rat(-6610999, 2479128), True, MINUS_SIGN + '6610999/2479128');
  Test('2/7 ⋅ 5/1 ⋅ 5/9 ⋅ 3/7 ⋅ 7/2 ⋅ 2/7 ⋅ 1/3 ⋅ 6/4 ⋅ 7/2 ⋅ 4/6 ⋅ 9/8 ⋅ 2/7 ⋅ 7/1 ⋅ 4/5 ⋅ 6/8', Rat(15, 28), True, '15/28');
  Test('2/7 ⋅ 5/1 ⋅ 5/9 ⋅ 3/7 ⋅ 7/2 ⋅ 2/7 ⋅ 1/3 ⋅ 6/0 ⋅ 7/2 ⋅ 4/6 ⋅ 9/8 ⋅ 2/7 ⋅ 7/1 ⋅ 4/5 ⋅ 6/8', failure, 'division by zero');
  Test('598 ⋅ 752/411856', Rat(28106, 25741), True, '28106/25741');
  Test('752/411856 ⋅ 598', Rat(28106, 25741), True, '28106/25741');
  Test('0 ⋅ 752/411856', 0, True, '0');
  Test('0 ⋅ (752/411856)', Rat(0, 1), True, '0');

//  Test('9223372036854775806/9223372036854775807 + 1/9223372036854775807', Rat(1, 1), True, '1');

  Test('SetNumberBase(SetMinLength(SetDigitGrouping(255/256, 2), 8), 16)', Rat(255, 256), True, fs('00 00 00 FF/00 00 01 00'));


  //
  // Real numbers
  //

  Test('3.1415', 3.1415, True, '3.1415');
  Test('-3.1415', -3.1415, True, MINUS_SIGN + '3.1415');

  Test('3.141592653589793238', 3.141592653589793238, True, '3.14159265359');
  Test('-3.141592653589793238', -3.141592653589793238, True, MINUS_SIGN + '3.14159265359');

  Test('3', 3, True, '3');
  Test('3.', 3.0, True, '3');

  Test('-3', -3, True, MINUS_SIGN + '3');
  Test('-3.', -3.0, True, MINUS_SIGN + '3');

  Test('.1415', 0.1415, True, '0.1415');
  Test('-.1415', -0.1415, True, MINUS_SIGN + '0.1415');

  Test('.', 0.0, True, '0');
  Test('+.', 0.0, True, '0');
  Test('-.', 0.0, True, '0');
  Test('.+.', 0.0, True, '0');

  Test('123456.789', 123456.789, True, '123456.789');
  Test('-123456.789', -123456.789, True, MINUS_SIGN + '123456.789');

  Test('1/2', Rat(1, 2), True, '1/2');
  Test('1./2', 0.5, True, '0.5');
  Test('1/2.', 0.5, True, '0.5');

  Test('1/3', Rat(1, 3), True, '1/3');
  Test('1./3', 1/3, True, '0.333333333333');
  Test('1/3.', 1/3, True, '0.333333333333');

  Test('-1/2', Rat(-1, 2), True, MINUS_SIGN + '1/2');
  Test('-1./2', -0.5, True, MINUS_SIGN + '0.5');
  Test('-1/2.', -0.5, True, MINUS_SIGN + '0.5');

  Test('-1/3', Rat(-1, 3), True, MINUS_SIGN + '1/3');
  Test('-1./3', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('-1/3.', -1/3, True, MINUS_SIGN + '0.333333333333');

  // Format: default, number of digits

  Test('1./3', 1/3, True, '0.333333333333');
  Test('1./3 \ 2', 1/3, True, '0.33');
  Test('1./3 \ 3', 1/3, True, '0.333');
  Test('1./3 \ 4', 1/3, True, '0.3333');
  Test('1./3 \ 5', 1/3, True, '0.33333');
  Test('1./3 \ 12', 1/3, True, '0.333333333333');
  Test('1./3 \ 16', 1/3, True, '0.3333333333333333');

  Test('-1./3', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('-1./3 \ 2', -1/3, True, MINUS_SIGN + '0.33');
  Test('-1./3 \ 3', -1/3, True, MINUS_SIGN + '0.333');
  Test('-1./3 \ 4', -1/3, True, MINUS_SIGN + '0.3333');
  Test('-1./3 \ 5', -1/3, True, MINUS_SIGN + '0.33333');
  Test('-1./3 \ 12', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('-1./3 \ 16', -1/3, True, MINUS_SIGN + '0.3333333333333333');

  Test('1./3', 1/3, True, '0.333333333333'); // operator \ maps to SetMaxLen
  Test('SetMaxLen(1./3, 2)', 1/3, True, '0.33');
  Test('SetMaxLen(1./3, 3)', 1/3, True, '0.333');
  Test('SetMaxLen(1./3, 4)', 1/3, True, '0.3333');
  Test('SetMaxLen(1./3, 5)', 1/3, True, '0.33333');
  Test('SetMaxLen(1./3, 12)', 1/3, True, '0.333333333333');
  Test('SetMaxLen(1./3, 16)', 1/3, True, '0.3333333333333333');

  Test('-1./3', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('SetMaxLen(-1./3, 2)', -1/3, True, MINUS_SIGN + '0.33');
  Test('SetMaxLen(-1./3, 3)', -1/3, True, MINUS_SIGN + '0.333');
  Test('SetMaxLen(-1./3, 4)', -1/3, True, MINUS_SIGN + '0.3333');
  Test('SetMaxLen(-1./3, 5)', -1/3, True, MINUS_SIGN + '0.33333');
  Test('SetMaxLen(-1./3, 12)', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('SetMaxLen(-1./3, 16)', -1/3, True, MINUS_SIGN + '0.3333333333333333');

  Test('1./3', 1/3, True, '0.333333333333'); // SetMaxLen works like SetNumDigits when arg 1 is a number and arg 2 is >= 0
  Test('SetNumDigits(1./3, 2)', 1/3, True, '0.33');
  Test('SetNumDigits(1./3, 3)', 1/3, True, '0.333');
  Test('SetNumDigits(1./3, 4)', 1/3, True, '0.3333');
  Test('SetNumDigits(1./3, 5)', 1/3, True, '0.33333');
  Test('SetNumDigits(1./3, 12)', 1/3, True, '0.333333333333');
  Test('SetNumDigits(1./3, 16)', 1/3, True, '0.3333333333333333');

  Test('-1./3', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('SetNumDigits(-1./3, 2)', -1/3, True, MINUS_SIGN + '0.33');
  Test('SetNumDigits(-1./3, 3)', -1/3, True, MINUS_SIGN + '0.333');
  Test('SetNumDigits(-1./3, 4)', -1/3, True, MINUS_SIGN + '0.3333');
  Test('SetNumDigits(-1./3, 5)', -1/3, True, MINUS_SIGN + '0.33333');
  Test('SetNumDigits(-1./3, 12)', -1/3, True, MINUS_SIGN + '0.333333333333');
  Test('SetNumDigits(-1./3, 16)', -1/3, True, MINUS_SIGN + '0.3333333333333333');

  Test('SetNumDigits(1./3, -1)', 1/3, True, '0.333333333333'); // SetNumDigits: negative count means inherit
  Test('SetMaxLen(1./3, -1)', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.'); // SetMaxLength requires a non-negative second argument
  Test('1./3 \ -1', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.'); // SetMaxLength requires a non-negative second argument

  Test('SetNumDigits(1./3, "a")', failure, 'An object of type integer was expected as argument 2, but an object of type string was given.');
  Test('SetMaxLen(1./3, "a")', failure, 'An object of type integer was expected as argument 2, but an object of type string was given.');
  Test('1./3 \ "a"', failure, 'An object of type integer was expected as argument 2, but an object of type string was given.');

  Test('SetNumDigits(1./3, 6, 10)', failure, 'Too many arguments.');
  Test('SetNumDigits(1./3)', failure, 'Too few arguments. A required argument of type integer is missing.');

  Test('2./3', 2/3, True, '0.666666666667');
  Test('2./3 \ 2', 2/3, True, '0.67');
  Test('2./3 \ 3', 2/3, True, '0.667');
  Test('2./3 \ 4', 2/3, True, '0.6667');
  Test('2./3 \ 5', 2/3, True, '0.66667');
  Test('2./3 \ 12', 2/3, True, '0.666666666667');
  Test('2./3 \ 16', 2/3, True, '0.6666666666666667');

  Test('-2./3', -2/3, True, MINUS_SIGN + '0.666666666667');
  Test('-2./3 \ 2', -2/3, True, MINUS_SIGN + '0.67');
  Test('-2./3 \ 3', -2/3, True, MINUS_SIGN + '0.667');
  Test('-2./3 \ 4', -2/3, True, MINUS_SIGN + '0.6667');
  Test('-2./3 \ 5', -2/3, True, MINUS_SIGN + '0.66667');
  Test('-2./3 \ 12', -2/3, True, MINUS_SIGN + '0.666666666667');
  Test('-2./3 \ 16', -2/3, True, MINUS_SIGN + '0.6666666666666667');

  // Exp literals and default format's exp notation

  Test('7E20', 7E20, True, mm('7*10^20'));
  Test('1E20 + 7E20', 8E20, True, mm('8*10^20'));
  Test('7E-20', 7E-20, True, mm('7*10^-20'));
  Eps; Test('1E-20 + 7E-20', 8E-20, True, mm('8*10^-20'));
  Test('123.45E20', 123.45E20, True, mm('1.2345*10^22'));
  Test('123.45E-20', 123.45E-20, True, mm('1.2345*10^-18'));
  Test('-123.45E20', -123.45E20, True, mm('-1.2345*10^22'));
  Test('-123.45E-20', -123.45E-20, True, mm('-1.2345*10^-18'));
  Test('3E3 + 2E2 + 1E1 + 0E0 + 1E-1 + 2E-2 + 3E-3', 3210.123, True, mm('3210.123'));
  Test('-3E3 - 2E2 - 1E1 - 0E0 - 1E-1 - 2E-2 - 3E-3', -3210.123, True, mm('-3210.123'));
  Test('1E0', 1.0, True, '1');
  Test('7E0', 7.0, True, '7');
  Test('123456.123456E0', 123456.123456, True, '123456.123456');
  Test('-123456.123456E0', -123456.123456, True, MINUS_SIGN + '123456.123456');
  Test('12300000000000000000000000000000000000000000', 1.23E43, True, mm('1.23*10^43'));
  Test('-12300000000000000000000000000000000000000000', -1.23E43, True, mm('-1.23*10^43'));
  Test('0.0000000000000000000123', 1.23E-20, True, mm('1.23*10^-20'));
  Test('-0.0000000000000000000123', -1.23E-20, True, mm('-1.23*10^-20'));
  Test('1E20', 1E20, True, mm('1*10^20')); // a future version might skip the "1*" part
  Test('1E-20', 1E-20, True, mm('1*10^-20')); // -"-

  Test('123456.', 123456.0, True, '123456');
  Test('123456. \ 8', 123456.0, True, '123456');
  Test('123456. \ 6', 123456.0, True, '123456');
  Test('123456. \ 5', 123456.0, True, mm('1.2346*10^5'));
  Test('123456. \ 4', 123456.0, True, mm('1.235*10^5'));
  Test('123456. \ 3', 123456.0, True, mm('1.23*10^5'));
  Test('123456. \ 2', 123456.0, True, mm('1.2*10^5'));

  Test('-123456.', -123456.0, True, MINUS_SIGN + '123456');
  Test('-123456. \ 8', -123456.0, True, MINUS_SIGN + '123456');
  Test('-123456. \ 6', -123456.0, True, MINUS_SIGN + '123456');
  Test('-123456. \ 5', -123456.0, True, mm('-1.2346*10^5'));
  Test('-123456. \ 4', -123456.0, True, mm('-1.235*10^5'));
  Test('-123456. \ 3', -123456.0, True, mm('-1.23*10^5'));
  Test('-123456. \ 2', -123456.0, True, mm('-1.2*10^5'));

  // Format: default, pretty exp notation

  Test('7E20', 7E20, True, mm('7*10^20'));
  Test('SetPrettyExp(7E20, true)', 7E20, True, mm('7*10^20'));
  Test('SetPrettyExp(7E20, false)', 7E20, True, mm('7E20'));

  Test('7E-20', 7E-20, True, mm('7*10^-20'));
  Test('SetPrettyExp(7E-20, true)', 7E-20, True, mm('7*10^-20'));
  Test('SetPrettyExp(7E-20, false)', 7E-20, True, mm('7E-20'));

  Test('-7E20', -7E20, True, mm('-7*10^20'));
  Test('SetPrettyExp(-7E20, true)', -7E20, True, mm('-7*10^20'));
  Test('SetPrettyExp(-7E20, false)', -7E20, True, mm('-7E20'));

  Test('-7E-20', -7E-20, True, mm('-7*10^-20'));
  Test('SetPrettyExp(-7E-20, true)', -7E-20, True, mm('-7*10^-20'));
  Test('SetPrettyExp(-7E-20, false)', -7E-20, True, mm('-7E-20'));

  Test('-123456. \ 2', -123456.0, True, mm('-1.2*10^5'));
  Test('SetPrettyExp(-123456., true) \ 2', -123456.0, True, mm('-1.2*10^5'));
  Test('SetPrettyExp(-123456., false) \ 2', -123456.0, True, mm('-1.2E5'));
  Test('SetPrettyExp(-123456. \ 2, false)', -123456.0, True, mm('-1.2E5'));

  Test('SetPrettyExp(7E20, 7)', failure, 'An object of type boolean was expected as argument 2, but an object of type integer was given.');
  Test('SetPrettyExp(7E20)', failure, 'Too few arguments. A required argument of type boolean is missing.');
  Test('SetPrettyExp(7E20, true, 2)', failure, 'Too many arguments.');

  // Format: fixed, number of digits

  Test('123.45678', 123.45678, True, '123.45678');
  Test('SetNumberFormat(123.45678, "inherited")', 123.45678, True, '123.45678');
  Test('SetNumberFormat(123.45678, "default")', 123.45678, True, '123.45678');
  Test('SetNumberFormat(123.45678, "fixed")', 123.45678, True, '123.456780000000');
  Test('SetNumberFormat(123.45678, "fixed") \ 10', 123.45678, True, '123.4567800000');
  Test('SetNumberFormat(123.45678, "fixed") \ 8', 123.45678, True, '123.45678000');
  Test('SetNumberFormat(123.45678, "fixed") \ 6', 123.45678, True, '123.456780');
  Test('SetNumberFormat(123.45678, "fixed") \ 3', 123.45678, True, '123.457');
  Test('SetNumberFormat(123.45678, "fixed") \ 2', 123.45678, True, '123.46');
  Test('SetNumberFormat(123.45678, "fixed") \ 1', 123.45678, True, '123.5');
  Test('SetNumberFormat(123.45678, "fixed") \ 0', 123.45678, True, '123');

  Test('SetNumberFormat(123.45678, "default") \ 10', 123.45678, True, '123.45678');
  Test('SetNumberFormat(123.45678, "default") \ 8', 123.45678, True, '123.45678');
  Test('SetNumberFormat(123.45678, "default") \ 6', 123.45678, True, '123.457');
  Test('SetNumberFormat(123.45678, "default") \ 3', 123.45678, True, '123');
  Test('SetNumberFormat(123.45678, "default") \ 2', 123.45678, True, mm('1.2*10^2'));

  Test('-123.45678', -123.45678, True, MINUS_SIGN + '123.45678');
  Test('SetNumberFormat(-123.45678, "inherited")', -123.45678, True, MINUS_SIGN + '123.45678');
  Test('SetNumberFormat(-123.45678, "default")', -123.45678, True, MINUS_SIGN + '123.45678');
  Test('SetNumberFormat(-123.45678, "fixed")', -123.45678, True, MINUS_SIGN + '123.456780000000');
  Test('SetNumberFormat(-123.45678, "fixed") \ 10', -123.45678, True, MINUS_SIGN + '123.4567800000');
  Test('SetNumberFormat(-123.45678, "fixed") \ 8', -123.45678, True, MINUS_SIGN + '123.45678000');
  Test('SetNumberFormat(-123.45678, "fixed") \ 6', -123.45678, True, MINUS_SIGN + '123.456780');
  Test('SetNumberFormat(-123.45678, "fixed") \ 3', -123.45678, True, MINUS_SIGN + '123.457');
  Test('SetNumberFormat(-123.45678, "fixed") \ 2', -123.45678, True, MINUS_SIGN + '123.46');
  Test('SetNumberFormat(-123.45678, "fixed") \ 1', -123.45678, True, MINUS_SIGN + '123.5');
  Test('SetNumberFormat(-123.45678, "fixed") \ 0', -123.45678, True, MINUS_SIGN + '123');

  Test('SetNumberFormat(-123.45678, "default") \ 10', -123.45678, True, MINUS_SIGN + '123.45678');
  Test('SetNumberFormat(-123.45678, "default") \ 8', -123.45678, True, MINUS_SIGN + '123.45678');
  Test('SetNumberFormat(-123.45678, "default") \ 6', -123.45678, True, MINUS_SIGN + '123.457');
  Test('SetNumberFormat(-123.45678, "default") \ 3', -123.45678, True, MINUS_SIGN + '123');
  Test('SetNumberFormat(-123.45678, "default") \ 2', -123.45678, True, mm('-1.2*10^2'));

  // Format: fixed, large and small numbers

  Test('SetNumberFormat(123.456E20, "fixed")', 123.456E20, True, mm('1.23456*10^22')); // reasonable to give up "fixed"
  Test('SetNumberFormat(-123.456E20, "fixed")', -123.456E20, True, mm('-1.23456*10^22'));

  Test('SetNumberFormat(123.456E-20, "fixed") \ 10', 123.456E-20, True, mm('0.0000000000')); // obvious
  Test('SetNumberFormat(-123.456E-20, "fixed") \ 10', -123.456E-20, True, mm('0.0000000000'));

  // Format: scientific

  Test('123.4567', 123.4567, True, '123.4567');
  Test('SetNumberFormat(123.4567, "default") \ 10', 123.4567, True, mm('123.4567'));
  Test('SetNumberFormat(123.4567, "fixed") \ 10', 123.4567, True, mm('123.4567000000'));
  Test('SetNumberFormat(123.4567, "scientific") \ 10', 123.4567, True, mm('1.234567000*10^2'));

  Test('SetNumberFormat(123.4567, "default") \ 8', 123.4567, True, mm('123.4567'));
  Test('SetNumberFormat(123.4567, "fixed") \ 8', 123.4567, True, mm('123.45670000'));
  Test('SetNumberFormat(123.4567, "scientific") \ 8', 123.4567, True, mm('1.2345670*10^2'));

  Test('SetNumberFormat(123.4567, "default") \ 6', 123.4567, True, mm('123.457'));
  Test('SetNumberFormat(123.4567, "fixed") \ 6', 123.4567, True, mm('123.456700'));
  Test('SetNumberFormat(123.4567, "scientific") \ 6', 123.4567, True, mm('1.23457*10^2'));

  Test('SetNumberFormat(123.4567, "default") \ 4', 123.4567, True, mm('123.5'));
  Test('SetNumberFormat(123.4567, "fixed") \ 4', 123.4567, True, mm('123.4567'));
  Test('SetNumberFormat(123.4567, "scientific") \ 4', 123.4567, True, mm('1.235*10^2'));

  Test('SetNumberFormat(123.4567, "default") \ 2', 123.4567, True, mm('1.2*10^2'));
  Test('SetNumberFormat(123.4567, "fixed") \ 2', 123.4567, True, mm('123.46'));
  Test('SetNumberFormat(123.4567, "scientific") \ 2', 123.4567, True, mm('1.2*10^2'));

  Test('-123.4567', -123.4567, True, MINUS_SIGN + '123.4567');
  Test('SetNumberFormat(-123.4567, "default") \ 10', -123.4567, True, mm('-123.4567'));
  Test('SetNumberFormat(-123.4567, "fixed") \ 10', -123.4567, True, mm('-123.4567000000'));
  Test('SetNumberFormat(-123.4567, "scientific") \ 10', -123.4567, True, mm('-1.234567000*10^2'));

  Test('SetNumberFormat(-123.4567, "default") \ 8', -123.4567, True, mm('-123.4567'));
  Test('SetNumberFormat(-123.4567, "fixed") \ 8', -123.4567, True, mm('-123.45670000'));
  Test('SetNumberFormat(-123.4567, "scientific") \ 8', -123.4567, True, mm('-1.2345670*10^2'));

  Test('SetNumberFormat(-123.4567, "default") \ 6', -123.4567, True, mm('-123.457'));
  Test('SetNumberFormat(-123.4567, "fixed") \ 6', -123.4567, True, mm('-123.456700'));
  Test('SetNumberFormat(-123.4567, "scientific") \ 6', -123.4567, True, mm('-1.23457*10^2'));

  Test('SetNumberFormat(-123.4567, "default") \ 4', -123.4567, True, mm('-123.5'));
  Test('SetNumberFormat(-123.4567, "fixed") \ 4', -123.4567, True, mm('-123.4567'));
  Test('SetNumberFormat(-123.4567, "scientific") \ 4', -123.4567, True, mm('-1.235*10^2'));

  Test('SetNumberFormat(-123.4567, "default") \ 2', -123.4567, True, mm('-1.2*10^2'));
  Test('SetNumberFormat(-123.4567, "fixed") \ 2', -123.4567, True, mm('-123.46'));
  Test('SetNumberFormat(-123.4567, "scientific") \ 2', -123.4567, True, mm('-1.2*10^2'));

  // Format: scientific, pretty exp off

  Test('SetPrettyExp(SetNumberFormat(-123.4567, "default"), false) \ 2', -123.4567, True, mm('-1.2E2'));
  Test('SetPrettyExp(SetNumberFormat(-123.4567, "fixed"), false) \ 2', -123.4567, True, mm('-123.46'));
  Test('SetPrettyExp(SetNumberFormat(-123.4567, "scientific"), false) \ 2', -123.4567, True, mm('-1.2E+2'));

  Test('SetPrettyExp(1E20, false)', 1E20, True, '1E20');
  Test('SetPrettyExp(SetNumberFormat(1E20, "default") \ 4, false)', 1E20, True, '1E20');
  Test('SetPrettyExp(SetNumberFormat(1E20, "scientific") \ 4, false)', 1E20, True, '1.000E+20');

  Test('SetPrettyExp(-1E20, false)', -1E20, True, mm('-1E20'));
  Test('SetPrettyExp(SetNumberFormat(-1E20, "default") \ 4, false)', -1E20, True, mm('-1E20'));
  Test('SetPrettyExp(SetNumberFormat(-1E20, "scientific") \ 4, false)', -1E20, True, mm('-1.000E+20'));

  Test('SetPrettyExp(1E-20, false)', 1E-20, True, mm('1E-20'));
  Test('SetPrettyExp(SetNumberFormat(1E-20, "default") \ 4, false)', 1E-20, True, mm('1E-20'));
  Test('SetPrettyExp(SetNumberFormat(1E-20, "scientific") \ 4, false)', 1E-20, True, mm('1.000E-20'));

  // Format: digit grouping (default style, no exps)

  Test('SetDigitGrouping(123456.123456, -1)', 123456.123456, True, '123456.123456');
  Test('SetDigitGrouping(123456.123456, 0)', 123456.123456, True, '123456.123456');
  Test('SetDigitGrouping(123456.123456, 1)', 123456.123456, True, fs('1 2 3 4 5 6.1 2 3 4 5 6'));
  Test('SetDigitGrouping(123456.123456, 2)', 123456.123456, True, fs('12 34 56.12 34 56'));
  Test('SetDigitGrouping(123456.123456, 3)', 123456.123456, True, fs('123 456.123 456'));
  Test('SetDigitGrouping(123456.123456, 4)', 123456.123456, True, fs('12 3456.1234 56'));
  Test('SetDigitGrouping(123456.123456, 5)', 123456.123456, True, fs('1 23456.12345 6'));
  Test('SetDigitGrouping(123456.123456, 6)', 123456.123456, True, fs('123456.123456'));
  Test('SetDigitGrouping(123456.123456, 7)', 123456.123456, True, fs('123456.123456'));
  Test('SetDigitGrouping(123456.123456, 8)', 123456.123456, True, fs('123456.123456'));

  Test('SetDigitGrouping(-123456.123456, -1)', -123456.123456, True, MINUS_SIGN + '123456.123456');
  Test('SetDigitGrouping(-123456.123456, 0)', -123456.123456, True, MINUS_SIGN + '123456.123456');
  Test('SetDigitGrouping(-123456.123456, 1)', -123456.123456, True, MINUS_SIGN + fs('1 2 3 4 5 6.1 2 3 4 5 6'));
  Test('SetDigitGrouping(-123456.123456, 2)', -123456.123456, True, MINUS_SIGN + fs('12 34 56.12 34 56'));
  Test('SetDigitGrouping(-123456.123456, 3)', -123456.123456, True, MINUS_SIGN + fs('123 456.123 456'));
  Test('SetDigitGrouping(-123456.123456, 4)', -123456.123456, True, MINUS_SIGN + fs('12 3456.1234 56'));
  Test('SetDigitGrouping(-123456.123456, 5)', -123456.123456, True, MINUS_SIGN + fs('1 23456.12345 6'));
  Test('SetDigitGrouping(-123456.123456, 6)', -123456.123456, True, MINUS_SIGN + fs('123456.123456'));
  Test('SetDigitGrouping(-123456.123456, 7)', -123456.123456, True, MINUS_SIGN + fs('123456.123456'));
  Test('SetDigitGrouping(-123456.123456, 8)', -123456.123456, True, MINUS_SIGN + fs('123456.123456'));

  // Format: digit grouping (default style, with exps)

  Test('SetDigitGrouping(1.23456123456E20, -1)', 1.23456123456E20, True, mm(fs('1.23456123456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 0)', 1.23456123456E20, True, mm(fs('1.23456123456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 1)', 1.23456123456E20, True, mm(fs('1.2 3 4 5 6 1 2 3 4 5 6*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 2)', 1.23456123456E20, True, mm(fs('1.23 45 61 23 45 6*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 3)', 1.23456123456E20, True, mm(fs('1.234 561 234 56*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 4)', 1.23456123456E20, True, mm(fs('1.2345 6123 456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 5)', 1.23456123456E20, True, mm(fs('1.23456 12345 6*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 6)', 1.23456123456E20, True, mm(fs('1.234561 23456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 7)', 1.23456123456E20, True, mm(fs('1.2345612 3456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 8)', 1.23456123456E20, True, mm(fs('1.23456123 456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 9)', 1.23456123456E20, True, mm(fs('1.234561234 56*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 10)', 1.23456123456E20, True, mm(fs('1.2345612345 6*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 11)', 1.23456123456E20, True, mm(fs('1.23456123456*10^20')));
  Test('SetDigitGrouping(1.23456123456E20, 12)', 1.23456123456E20, True, mm(fs('1.23456123456*10^20')));

  Test('SetDigitGrouping(1.23456123456E-20, -1)', 1.23456123456E-20, True, mm(fs('1.23456123456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 0)', 1.23456123456E-20, True, mm(fs('1.23456123456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 1)', 1.23456123456E-20, True, mm(fs('1.2 3 4 5 6 1 2 3 4 5 6*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 2)', 1.23456123456E-20, True, mm(fs('1.23 45 61 23 45 6*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 3)', 1.23456123456E-20, True, mm(fs('1.234 561 234 56*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 4)', 1.23456123456E-20, True, mm(fs('1.2345 6123 456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 5)', 1.23456123456E-20, True, mm(fs('1.23456 12345 6*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 6)', 1.23456123456E-20, True, mm(fs('1.234561 23456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 7)', 1.23456123456E-20, True, mm(fs('1.2345612 3456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 8)', 1.23456123456E-20, True, mm(fs('1.23456123 456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 9)', 1.23456123456E-20, True, mm(fs('1.234561234 56*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 10)', 1.23456123456E-20, True, mm(fs('1.2345612345 6*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 11)', 1.23456123456E-20, True, mm(fs('1.23456123456*10^-20')));
  Test('SetDigitGrouping(1.23456123456E-20, 12)', 1.23456123456E-20, True, mm(fs('1.23456123456*10^-20')));

  Test('SetDigitGrouping(-1.23456123456E20, -1)', -1.23456123456E20, True, mm(fs('-1.23456123456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 0)', -1.23456123456E20, True, mm(fs('-1.23456123456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 1)', -1.23456123456E20, True, mm(fs('-1.2 3 4 5 6 1 2 3 4 5 6*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 2)', -1.23456123456E20, True, mm(fs('-1.23 45 61 23 45 6*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 3)', -1.23456123456E20, True, mm(fs('-1.234 561 234 56*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 4)', -1.23456123456E20, True, mm(fs('-1.2345 6123 456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 5)', -1.23456123456E20, True, mm(fs('-1.23456 12345 6*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 6)', -1.23456123456E20, True, mm(fs('-1.234561 23456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 7)', -1.23456123456E20, True, mm(fs('-1.2345612 3456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 8)', -1.23456123456E20, True, mm(fs('-1.23456123 456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 9)', -1.23456123456E20, True, mm(fs('-1.234561234 56*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 10)', -1.23456123456E20, True, mm(fs('-1.2345612345 6*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 11)', -1.23456123456E20, True, mm(fs('-1.23456123456*10^20')));
  Test('SetDigitGrouping(-1.23456123456E20, 12)', -1.23456123456E20, True, mm(fs('-1.23456123456*10^20')));

  Test('SetDigitGrouping(-1.23456123456E-20, -1)', -1.23456123456E-20, True, mm(fs('-1.23456123456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 0)', -1.23456123456E-20, True, mm(fs('-1.23456123456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 1)', -1.23456123456E-20, True, mm(fs('-1.2 3 4 5 6 1 2 3 4 5 6*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 2)', -1.23456123456E-20, True, mm(fs('-1.23 45 61 23 45 6*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 3)', -1.23456123456E-20, True, mm(fs('-1.234 561 234 56*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 4)', -1.23456123456E-20, True, mm(fs('-1.2345 6123 456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 5)', -1.23456123456E-20, True, mm(fs('-1.23456 12345 6*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 6)', -1.23456123456E-20, True, mm(fs('-1.234561 23456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 7)', -1.23456123456E-20, True, mm(fs('-1.2345612 3456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 8)', -1.23456123456E-20, True, mm(fs('-1.23456123 456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 9)', -1.23456123456E-20, True, mm(fs('-1.234561234 56*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 10)', -1.23456123456E-20, True, mm(fs('-1.2345612345 6*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 11)', -1.23456123456E-20, True, mm(fs('-1.23456123456*10^-20')));
  Test('SetDigitGrouping(-1.23456123456E-20, 12)', -1.23456123456E-20, True, mm(fs('-1.23456123456*10^-20')));

  // Format: digit grouping (fixed)

  Test('SetNumberFormat(1234.56789, "fixed") \ 6', 1234.56789, True, '1234.567890');
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, -1)', 1234.56789, True, fs('1234.567890'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 0)', 1234.56789, True, fs('1234.567890'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 1)', 1234.56789, True, fs('1 2 3 4.5 6 7 8 9 0'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 2)', 1234.56789, True, fs('12 34.56 78 90'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 3)', 1234.56789, True, fs('1 234.567 890'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 4)', 1234.56789, True, fs('1234.5678 90'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 5)', 1234.56789, True, fs('1234.56789 0'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 6)', 1234.56789, True, fs('1234.567890'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 7)', 1234.56789, True, fs('1234.567890'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 6, 8)', 1234.56789, True, fs('1234.567890'));

  Test('SetNumberFormat(1234.56789, "fixed") \ 10', 1234.56789, True, '1234.5678900000');
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, -1)', 1234.56789, True, fs('1234.5678900000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 0)', 1234.56789, True, fs('1234.5678900000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 1)', 1234.56789, True, fs('1 2 3 4.5 6 7 8 9 0 0 0 0 0'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 2)', 1234.56789, True, fs('12 34.56 78 90 00 00'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 3)', 1234.56789, True, fs('1 234.567 890 000 0'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 4)', 1234.56789, True, fs('1234.5678 9000 00'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 5)', 1234.56789, True, fs('1234.56789 00000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 6)', 1234.56789, True, fs('1234.567890 0000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 7)', 1234.56789, True, fs('1234.5678900 000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 8)', 1234.56789, True, fs('1234.56789000 00'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 9)', 1234.56789, True, fs('1234.567890000 0'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 10)', 1234.56789, True, fs('1234.5678900000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 11)', 1234.56789, True, fs('1234.5678900000'));
  Test('SetDigitGrouping(SetNumberFormat(1234.56789, "fixed") \ 10, 12)', 1234.56789, True, fs('1234.5678900000'));

  Test('SetNumberFormat(-1234.56789, "fixed") \ 6', -1234.56789, True, mm('-1234.567890'));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, -1)', -1234.56789, True, fs(mm('-1234.567890')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 0)', -1234.56789, True, fs(mm('-1234.567890')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 1)', -1234.56789, True, fs(mm('-1 2 3 4.5 6 7 8 9 0')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 2)', -1234.56789, True, fs(mm('-12 34.56 78 90')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 3)', -1234.56789, True, fs(mm('-1 234.567 890')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 4)', -1234.56789, True, fs(mm('-1234.5678 90')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 5)', -1234.56789, True, fs(mm('-1234.56789 0')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 6)', -1234.56789, True, fs(mm('-1234.567890')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 7)', -1234.56789, True, fs(mm('-1234.567890')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 6, 8)', -1234.56789, True, fs(mm('-1234.567890')));

  Test('SetNumberFormat(-1234.56789, "fixed") \ 10', -1234.56789, True, mm('-1234.5678900000'));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, -1)', -1234.56789, True, fs(mm('-1234.5678900000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 0)', -1234.56789, True, fs(mm('-1234.5678900000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 1)', -1234.56789, True, fs(mm('-1 2 3 4.5 6 7 8 9 0 0 0 0 0')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 2)', -1234.56789, True, fs(mm('-12 34.56 78 90 00 00')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 3)', -1234.56789, True, fs(mm('-1 234.567 890 000 0')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 4)', -1234.56789, True, fs(mm('-1234.5678 9000 00')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 5)', -1234.56789, True, fs(mm('-1234.56789 00000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 6)', -1234.56789, True, fs(mm('-1234.567890 0000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 7)', -1234.56789, True, fs(mm('-1234.5678900 000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 8)', -1234.56789, True, fs(mm('-1234.56789000 00')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 9)', -1234.56789, True, fs(mm('-1234.567890000 0')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 10)', -1234.56789, True, fs(mm('-1234.5678900000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 11)', -1234.56789, True, fs(mm('-1234.5678900000')));
  Test('SetDigitGrouping(SetNumberFormat(-1234.56789, "fixed") \ 10, 12)', -1234.56789, True, fs(mm('-1234.5678900000')));


  //
  // Complex numbers
  //

  Test('i', ImaginaryUnit, True, 'i');
  Test('−i', -ImaginaryUnit, True, '−i');
  Test('77⋅i', 77*ImaginaryUnit, True, '77⋅i');
  Test('−77⋅i', -77*ImaginaryUnit, True, '−77⋅i');
  Test('−1⋅i', -ImaginaryUnit, True, '−i');
  Test('i^2', TASC(-1), True, mm('-1'));
  Test('1+i', 1 + ImaginaryUnit, True, mm('1 + i'));
  Test('7.5+i', 7.5 + ImaginaryUnit, True, mm('7.5 + i'));
  Test('7.5-i', 7.5 - ImaginaryUnit, True, mm('7.5 - i'));
  Test('2+3⋅i', 2 + 3*ImaginaryUnit, True, mm('2 + 3*i'));
  Test('-1+i', -1 + ImaginaryUnit, True, mm('-1 + i'));
  Test('-2+3⋅i', -2 + 3*ImaginaryUnit, True, mm('-2 + 3*i'));
  Test('1-i', 1 - ImaginaryUnit, True, mm('1 - i'));
  Test('2-3⋅i', 2 - 3*ImaginaryUnit, True, mm('2 - 3*i'));
  Test('-1-i', -1 - ImaginaryUnit, True, mm('-1 - i'));
  Test('-2-3⋅i', -2 - 3*ImaginaryUnit, True, mm('-2 - 3*i'));
  Test('sqrt(-1)', ImaginaryUnit, True, 'i');
  Eps; Test('i^i', TASC(exp(-pi/2)));
  Eps; Test('arcsin(-2)', -1.57079632679489662 + 1.31695789692481671*ImaginaryUnit);
  Test('1/3 + i/3', 1/3 + ImaginaryUnit/3, True, '0.333333333333 + 0.333333333333⋅i');
  Test('(1/3 + i/3) \ 5', 1/3 + ImaginaryUnit/3, True, '0.33333 + 0.33333⋅i');
  Test('(1/3 + i/3) \ 2', 1/3 + ImaginaryUnit/3, True, '0.33 + 0.33⋅i');


  //
  // Booleans
  //

  Test('true', true);
  Test('false', false);
  Test('true ∧ true ∧ true', true);
  Test('false ∧ true ∧ true', false);
  Test('true ∧ false ∧ true', false);
  Test('true ∧ true ∧ false', false);
  Test('false ∨ false ∨ false ∨ false', false);
  Test('false ∨ false ∨ true ∨ false', true);
  Test('¬false', true);
  Test('¬true', false);
  Test('¬¬¬¬¬¬¬¬¬¬true', true);
  Test('¬¬¬¬¬¬¬¬¬¬¬true', false);


  //
  // Strings
  //

  Test('"Lorem ipsum"', 'Lorem ipsum', True, 'Lorem ipsum');
  Test('"cat"', 'cat', True, 'cat');
  Test('""', '', True, '');
  Test('"Lorem" + " " + "ipsum"', 'Lorem ipsum', True, 'Lorem ipsum');
  Test('"Lorem" ~ " " ~ "ipsum"', 'Lorem ipsum', True, 'Lorem ipsum');
  Test('"cat" + "" + ""', 'cat', True, 'cat');
  Test('"cat" ~ "" ~ ""', 'cat', True, 'cat');
  Test('"" + "cat"', 'cat', True, 'cat');
  Test('"" ~ "cat"', 'cat', True, 'cat');
  Test('"" + ""', '', True, '');
  Test('"" ~ ""', '', True, '');

  _s2 := DupeString('cat ', 250) + '…';           Assert(_s2.Length - 1 = 1000);

  _s := 'cat' + DupeString(' cat', 100);
  Test('"' + _s + '"', _s, True, _s);

  _s := 'cat' + DupeString(' cat', 1000);
  Test('"' + _s + '"', _s, True, _s2);

  _s := 'cat' + DupeString(' cat', 10000);
  Test('"' + _s + '"', _s, True, _s2);

  _s := 'cat' + DupeString(' cat', 100000);
  Test('"' + _s + '"', _s, True, _s2);

  _s := 'cat' + DupeString(' cat', 1000000);
  Test('"' + _s + '"', _s, True, _s2);

  _s := 'cat' + DupeString(' cat', 10000000);
  Test('"' + _s + '"', _s, True, _s2);

  _s := 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
  Test('"' + _s + '"', _s, True, _s);
  Test('"' + _s + '" \11', _s, True, 'Lorem ipsum…');
  Test('"' + _s + '" \5', _s, True, 'Lorem…');
  Test('"' + _s + '" \2', _s, True, 'Lo…');
  Test('"' + _s + '" \1', _s, True, 'L…');

  Test('SetMaxLen("' + _s + '", 11)', _s, True, 'Lorem ipsum…');

  Test('"' + _s + '" \0', _s, True, _s);
  Test('SetMaxLen("' + _s + '", 0)', _s, True, _s);

  Test('"' + _s + '" \ -1', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.');
  Test('SetMaxLen("' + _s + '", -1)', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.');

  Test('"alfa" + ¶ + "beta"', 'alfa'#13#10'beta', True, 'alfa↲beta');
  TestSL('"alfa" + ¶ + "beta"', 'alfa↲beta');
  TestML('"alfa" + ¶ + "beta"', 'alfa'#13#10'beta');

  Test('"A new book named ""Cats""."', 'A new book named "Cats".', True, 'A new book named "Cats".');
  Test('"The empty string is """"."', 'The empty string is "".', True, 'The empty string is "".');
  Test('""""""', '""', True, '""');

  Test('"alfa beta', ESyntaxException, 'Unterminated string literal "alfa beta" starting at column 1.');
  Test('"alfa" + "beta', ESyntaxException, 'Unterminated string literal "beta" starting at column 10.');
  Test('"', ESyntaxException, 'Unterminated string literal "" starting at column 1.');
  Test('"""""', ESyntaxException, 'Unterminated string literal """""" starting at column 1.');

  Test('"Dogs are cute."[1]', 'D');
  Test('"Dogs are cute."[2]', 'o');
  Test('"Dogs are cute."[3]', 'g');
  Test('"Dogs are cute."[4]', 's');
  Test('"Dogs are cute."[5]', ' ');
  Test('"Dogs are cute."[6]', 'a');
  Test('"Dogs are cute."[7]', 'r');
  Test('"Dogs are cute."[8]', 'e');
  Test('"Dogs are cute."[9]', ' ');
  Test('"Dogs are cute."[10]', 'c');
  Test('"Dogs are cute."[11]', 'u');
  Test('"Dogs are cute."[12]', 't');
  Test('"Dogs are cute."[13]', 'e');
  Test('"Dogs are cute."[14]', '.');

  Test('"Dogs are cute."[15]', failure, 'Index 15 out of bounds.');

  Test('"Dogs are cute."[-1]', '.');
  Test('"Dogs are cute."[-2]', 'e');
  Test('"Dogs are cute."[-3]', 't');
  Test('"Dogs are cute."[-4]', 'u');
  Test('"Dogs are cute."[-5]', 'c');
  Test('"Dogs are cute."[-6]', ' ');
  Test('"Dogs are cute."[-7]', 'e');
  Test('"Dogs are cute."[-8]', 'r');
  Test('"Dogs are cute."[-9]', 'a');
  Test('"Dogs are cute."[-10]', ' ');
  Test('"Dogs are cute."[-11]', 's');
  Test('"Dogs are cute."[-12]', 'g');
  Test('"Dogs are cute."[-13]', 'o');
  Test('"Dogs are cute."[-14]', 'D');

  Test('"Dogs are cute."[-15]', failure, 'Index -15 out of bounds.');

  Test('"Dogs are cute."[0]', failure, 'Index 0 out of bounds.');

  Test('"Dogs are cute."[5] ≔ "G"', failure, 'Left side cannot be assigned to.');
  Test('"Dogs are cute."[-2] ≔ "G"', failure, 'Left side cannot be assigned to.');
  Test('"Dogs are cute."[25] ≔ "G"', failure, 'Left side cannot be assigned to.');
  Test('"Dogs are cute."[-25] ≔ "G"', failure, 'Left side cannot be assigned to.');
  Test('"Dogs are cute."[0] ≔ "G"', failure, 'Left side cannot be assigned to.');

  Test('("A" + "B")[1]', 'A');
  Test('("A" + "B")[2]', 'B');
  Test('("A" + "B")[3]', failure, 'Index 3 out of bounds.');

  Test('("A" + "B")[-1]', 'B');
  Test('("A" + "B")[-2]', 'A');
  Test('("A" + "B")[-3]', failure, 'Index -3 out of bounds.');

  Test('("A" + "B")[0]', failure, 'Index 0 out of bounds.');

  Test('""[-3]', failure, 'Index -3 out of bounds.');
  Test('""[-2]', failure, 'Index -2 out of bounds.');
  Test('""[-1]', failure, 'Index -1 out of bounds.');
  Test('""[0]', failure, 'Index 0 out of bounds.');
  Test('""[1]', failure, 'Index 1 out of bounds.');
  Test('""[2]', failure, 'Index 2 out of bounds.');
  Test('""[3]', failure, 'Index 3 out of bounds.');

  Test('struct("a": 42, "b": "dog").b[1]', 'd');
  Test('struct("a": 42, "b": "dog").b[2]', 'o');
  Test('struct("a": 42, "b": "dog").b[3]', 'g');
  Test('struct("a": 42, "b": "dog").b[4]', failure, 'Index 4 out of bounds.');

  Test('struct("a": 42, "b": "dog").b[-1]', 'g');
  Test('struct("a": 42, "b": "dog").b[-2]', 'o');
  Test('struct("a": 42, "b": "dog").b[-3]', 'd');
  Test('struct("a": 42, "b": "dog").b[-4]', failure, 'Index -4 out of bounds.');

  Test('struct("a": 42, "b": "dog").b[0]', failure, 'Index 0 out of bounds.');

  Test('struct("a": 42, "b": "dog").b[2] ≔ "a"', failure, 'Left side cannot be assigned to.');


  //
  // Real vectors
  //

  Test('❨1, 0, 0❩', [1, 0, 0]);                                                  // ❨❩
  Test('❨1, 2, 3❩', [1, 2, 3]);
  Test('❨1, -1❩', [1, -1]);
  Test('❨1❩', [1]);
  Test('❨0❩', [0]);
  Test('❨-1❩', [-1]);

  Test('❨2, −3, 1❩[1]', 2.0);
  Test('❨2, −3, 1❩[2]', -3.0);
  Test('❨2, −3, 1❩[3]', 1.0);
  Test('❨2, −3, 1❩[4]', failure, 'Index 4 out of bounds.');

  Test('❨2, −3, 1❩[-1]', 1.0);
  Test('❨2, −3, 1❩[-2]', -3.0);
  Test('❨2, −3, 1❩[-3]', 2.0);
  Test('❨2, −3, 1❩[-4]', failure, 'Index -4 out of bounds.');

  Test('❨2, −3, 1❩[0]', failure, 'Index 0 out of bounds.');

  Test('❨2, −3, 1❩[2] ≔ 3', failure, 'Left side cannot be assigned to.');
  Test('❨2, −3, 1❩[20] ≔ 3', failure, 'Left side cannot be assigned to.');

  Test('vector(1, 2, 3)', [1, 2, 3]);

  Test('❨1, 2, 3❩ + ❨10, 100, 1000❩', [11, 102, 1003]);

  TestSL('❨1, 2, 3❩', '(1, 2, 3)');
  TestML('❨1, 2, 3❩', ' ⎛1⎞'#13#10'e⎜2⎟'#13#10' ⎝3⎠');

  TestML('❨1❩', '(1)');
  TestML('❨1, 2❩', ' ⎛1⎞'#13#10'e⎝2⎠');
  TestML('❨1, 2, 3❩', ' ⎛1⎞'#13#10'e⎜2⎟'#13#10' ⎝3⎠');

  Test('SequenceVector(100)', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]);
  TestSL('SequenceVector(100)', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,'+' 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,'+' 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)');
  TestML('SequenceVector(100)', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,'+' 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,'+' 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)'); // (way) beyond default vertical until

  Test('SequenceVector(200)', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200]);
  TestSL('SequenceVector(200)', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, '+'33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, '+'67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, …)');
  TestML('SequenceVector(200)', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, '+'33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, '+'67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, …)'); // (way) beyond default vertical until

  Test('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)');

  Test('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 10', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 10', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)');

  Test('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 9', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 9', '(1, 2, 3, 4, 5, 6, 7, 8, 9, …)');

  Test('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 5', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 5', '(1, 2, 3, 4, 5, …)');

  Test('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 2', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 2', '(1, 2, …)');

  Test('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 1', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨1, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 1', '(1, …)');

  Test('❨1, 2, 3, 4, 5, 6❩', [1, 2, 3, 4, 5, 6]);
  TestSL('❨1, 2, 3, 4, 5, 6❩', '(1, 2, 3, 4, 5, 6)');
  TestML('❨1, 2, 3, 4, 5, 6❩', ' ⎛1⎞'#13#10' ⎜2⎟'#13#10' ⎜3⎟'#13#10'e⎜4⎟'#13#10' ⎜5⎟'#13#10' ⎝6⎠');

  Test('❨1, 2, 3, 4, 5, 6❩ \ 3', [1, 2, 3, 4, 5, 6]);
  TestSL('❨1, 2, 3, 4, 5, 6❩ \ 3', '(1, 2, 3, …)');
  TestML('❨1, 2, 3, 4, 5, 6❩ \ 3', ' ⎛1⎞'#13#10' ⎜2⎟'#13#10'e⎜3⎟'#13#10' ⎝⋮⎠');

  Test('❨❩', ESyntaxException, 'Empty bracket at column 1.'); // would make sense to allow syntactically, to get vector's error message instead
  Test('vector()', failure, 'A vector must have dimension at least one.');

  Test('❨1, 1/2, 1/3❩', [1, 1/2, 1/3]);
  TestML('❨1, 1/2, 1/3❩', ' ⎛      1       ⎞'#13#10'e⎜     0.5      ⎟'#13#10' ⎝0.333333333333⎠');
  TestML('SetNumDigits(❨1, 1/2, 1/3❩, 4)', ' ⎛  1   ⎞'#13#10'e⎜ 0.5  ⎟'#13#10' ⎝0.3333⎠');
  TestML('SetNumDigits(❨1/2, 1/3, 1/4❩, 4) \ 2', ' ⎛ 0.5  ⎞'#13#10'e⎜0.3333⎟'#13#10' ⎝  ⋮   ⎠');

  TestSL('❨1, 1/2, 1/3❩', '(1, 0.5, 0.333333333333)');
  TestSL('SetNumDigits(❨1, 1/2, 1/3❩, 4)', '(1, 0.5, 0.3333)');
  TestSL('SetNumDigits(❨1/2, 1/3, 1/4❩, 4) \ 2', '(0.5, 0.3333, …)');

  TestML('SetDigitGrouping(❨12432435, 65426277, 763763588, 62565245246, 415❩, 3)', ' ⎛  12 432 435  ⎞'#13#10' ⎜  65 426 277  ⎟'#13#10'e⎜ 763 763 588  ⎟'#13#10' ⎜62 565 245 246⎟'#13#10' ⎝     415      ⎠');
  TestSL('SetDigitGrouping(❨12432435, 65426277, 763763588, 62565245246, 415❩, 3)', '(12 432 435, 65 426 277, 763 763 588, 62 565 245 246, 415)');


  //
  // Complex vectors
  //

  Test('❨i, 0, 0❩', [ImaginaryUnit, 0, 0]);                                      // ❨❩
  Test('❨i, 2, 3❩', [ImaginaryUnit, 2, 3]);
  Test('❨i, -1❩', [ImaginaryUnit, -1]);
  Test('❨i❩', [ImaginaryUnit]);
  Test('❨-i❩', [-ImaginaryUnit]);

  TestML('❨i❩', '(i)');
  TestML('❨i, 2❩', ' ⎛i⎞'#13#10'e⎝2⎠');
  TestML('❨i, 2, 3❩', ' ⎛i⎞'#13#10'e⎜2⎟'#13#10' ⎝3⎠');

  Test('❨2, −3, i❩[1]', TASC(2.0));
  Test('❨2, −3, i❩[2]', TASC(-3.0));
  Test('❨2, −3, i❩[3]', ImaginaryUnit);
  Test('❨2, −3, i❩[4]', failure, 'Index 4 out of bounds.');

  Test('❨2, −3, i❩[-1]', ImaginaryUnit);
  Test('❨2, −3, i❩[-2]', TASC(-3.0));
  Test('❨2, −3, i❩[-3]', TASC(2.0));
  Test('❨2, −3, i❩[-4]', failure, 'Index -4 out of bounds.');

  Test('❨2, −3, i❩[0]', failure, 'Index 0 out of bounds.');

  Test('❨2, −3, i❩[2] ≔ 3', failure, 'Left side cannot be assigned to.');
  Test('❨2, −3, i❩[20] ≔ 3', failure, 'Left side cannot be assigned to.');

  Test('vector(i, 2, 3)', [ImaginaryUnit, 2, 3]);

  Test('❨i, 2, 3❩ + ❨10, 100, 1000❩', [ImaginaryUnit + 10, 102, 1003]);

  TestSL('❨i, 2, 3❩', '(i, 2, 3)');
  TestML('❨i, 2, 3❩', ' ⎛i⎞'#13#10'e⎜2⎟'#13#10' ⎝3⎠');

  Test('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩', [ImaginaryUnit, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩', '(i, 2, 3, 4, 5, 6, 7, 8, 9, 10)');

  Test('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 10', [ImaginaryUnit, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 10', '(i, 2, 3, 4, 5, 6, 7, 8, 9, 10)');

  Test('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 9', [ImaginaryUnit, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 9', '(i, 2, 3, 4, 5, 6, 7, 8, 9, …)');

  Test('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 5', [ImaginaryUnit, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 5', '(i, 2, 3, 4, 5, …)');

  Test('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 2', [ImaginaryUnit, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 2', '(i, 2, …)');

  Test('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 1', [ImaginaryUnit, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  TestSL('❨i, 2, 3, 4, 5, 6, 7, 8, 9, 10❩ \ 1', '(i, …)');

  Test('❨i, 2, 3, 4, 5, 6❩', [ImaginaryUnit, 2, 3, 4, 5, 6]);
  TestSL('❨i, 2, 3, 4, 5, 6❩', '(i, 2, 3, 4, 5, 6)');
  TestML('❨i, 2, 3, 4, 5, 6❩', ' ⎛i⎞'#13#10' ⎜2⎟'#13#10' ⎜3⎟'#13#10'e⎜4⎟'#13#10' ⎜5⎟'#13#10' ⎝6⎠');

  Test('❨i, 2, 3, 4, 5, 6❩ \ 3', [ImaginaryUnit, 2, 3, 4, 5, 6]);
  TestSL('❨i, 2, 3, 4, 5, 6❩ \ 3', '(i, 2, 3, …)');
  TestML('❨i, 2, 3, 4, 5, 6❩ \ 3', ' ⎛i⎞'#13#10' ⎜2⎟'#13#10'e⎜3⎟'#13#10' ⎝⋮⎠');

  Test('❨i, 1/2, 1/3❩', [ImaginaryUnit, 1/2, 1/3]);
  TestML('❨i, 1/2, 1/3❩', ' ⎛      i       ⎞'#13#10'e⎜     0.5      ⎟'#13#10' ⎝0.333333333333⎠');
  TestML('SetNumDigits(❨i, 1/2, 1/3❩, 4)', ' ⎛  i   ⎞'#13#10'e⎜ 0.5  ⎟'#13#10' ⎝0.3333⎠');
  TestML('SetNumDigits(❨i/2, 1/3, 1/4❩, 4) \ 2', ' ⎛0.5⋅i ⎞'#13#10'e⎜0.3333⎟'#13#10' ⎝  ⋮   ⎠');

  TestSL('❨i, 1/2, 1/3❩', '(i, 0.5, 0.333333333333)');
  TestSL('SetNumDigits(❨i, 1/2, 1/3❩, 4)', '(i, 0.5, 0.3333)');
  TestSL('SetNumDigits(❨i/2, 1/3, 1/4❩, 4) \ 2', '(0.5⋅i, 0.3333, …)');

  TestML('SetDigitGrouping(❨12432435, 65426277, 763763588, 62565245246⋅i, 415❩, 3)', ' ⎛   12 432 435   ⎞'#13#10' ⎜   65 426 277   ⎟'#13#10'e⎜  763 763 588   ⎟'#13#10' ⎜62 565 245 246⋅i⎟'#13#10' ⎝      415       ⎠');
  TestSL('SetDigitGrouping(❨12432435, 65426277, 763763588, 62565245246⋅i, 415❩, 3)', '(12 432 435, 65 426 277, 763 763 588, 62 565 245 246⋅i, 415)');


  //
  // Real matrices
  //

  Test('❨❨1, 2❩, ❨3, 4❩❩', 2, [1, 2, 3, 4]);                                     // ❨❩
  Test('matrix(2, 1, 2, 3, 4)', 2, [1, 2, 3, 4]);
  Test('matrix(1, 1, 2, 3, 4)', 1, [1, 2, 3, 4]);
  Test('matrix(4, 1, 2, 3, 4)', 4, [1, 2, 3, 4]);
  Test('matrix(3, 1, 2, 3, 4)', failure, 'Attempt to create a non-rectangular matrix.');
  Test('matrix(0, 1, 2, 3, 4)', failure, 'A positive integer was expected as argument 1, but "0" was given.');
  Test('❨❨1, 2❩, ❨3, 4❩❩ + ❨❨1, 10❩, ❨100, 1000❩❩', 2, [2, 12, 103, 1004]);
  Test('❨❨1❩, ❨2❩, ❨3❩❩', 1, [1, 2, 3]);
  Test('❨❨1, 2, 3❩❩', 3, [1, 2, 3]);
  Test('❨❨1, 2❩, ❨3❩❩', failure, 'Attempt to create a non-rectangular matrix.');
  Test('ZeroMatrix(3)', 3, [0, 0, 0, 0, 0, 0, 0, 0, 0]);
  Test('ZeroMatrix(2, 3)', 3, [0, 0, 0, 0, 0, 0]);
  Test('IdentityMatrix(3)', 3, [1, 0, 0, 0, 1, 0, 0, 0, 1]);
  TestML('IdentityMatrix(5)', '⎛1  0  0  0  0⎞'#13#10'⎜0  1  0  0  0⎟'#13#10'⎜0  0  1  0  0⎟'#13#10'⎜0  0  0  1  0⎟'#13#10'⎝0  0  0  0  1⎠');
  TestML('IdentityMatrix(5) \ 5', '⎛1  0  0  0  0⎞'#13#10'⎜0  1  0  0  0⎟'#13#10'⎜0  0  1  0  0⎟'#13#10'⎜0  0  0  1  0⎟'#13#10'⎝0  0  0  0  1⎠');
  TestML('IdentityMatrix(5) \ 4', '⎛1  0  0  0  ⋯⎞'#13#10'⎜0  1  0  0  ⋯⎟'#13#10'⎜0  0  1  0  ⋯⎟'#13#10'⎜0  0  0  1  ⋯⎟'#13#10'⎝⋮  ⋮  ⋮  ⋮  ⋱⎠');
  TestML('IdentityMatrix(5) \ 3', '⎛1  0  0  ⋯⎞'#13#10'⎜0  1  0  ⋯⎟'#13#10'⎜0  0  1  ⋯⎟'#13#10'⎝⋮  ⋮  ⋮  ⋱⎠');
  TestML('IdentityMatrix(5) \ 2', '⎛1  0  ⋯⎞'#13#10'⎜0  1  ⋯⎟'#13#10'⎝⋮  ⋮  ⋱⎠');
  TestML('IdentityMatrix(5) \ 1', '⎛1  ⋯⎞'#13#10'⎝⋮  ⋱⎠');
  TestML('IdentityMatrix(5) \ 0', '⎛1  0  0  0  0⎞'#13#10'⎜0  1  0  0  0⎟'#13#10'⎜0  0  1  0  0⎟'#13#10'⎜0  0  0  1  0⎟'#13#10'⎝0  0  0  0  1⎠');
  Test('IdentityMatrix(5) \ -1', failure, 'A non-negative integer was expected as argument 2, but "-1" was given.');
  TestSL('IdentityMatrix(5)', '((1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, 0, 1))');
  TestSL('IdentityMatrix(5) \ 5', '((1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, 0, 1))');
  TestSL('IdentityMatrix(5) \ 4', '((1, 0, 0, 0, …), (0, 1, 0, 0, …), (0, 0, 1, 0, …), (0, 0, 0, 1, …), …)');
  TestSL('IdentityMatrix(5) \ 3', '((1, 0, 0, …), (0, 1, 0, …), (0, 0, 1, …), …)');
  TestSL('IdentityMatrix(5) \ 2', '((1, 0, …), (0, 1, …), …)');
  TestSL('IdentityMatrix(5) \ 1', '((1, …), …)');
  TestSL('IdentityMatrix(5) \ 0', '((1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, 0, 1))');
  TestML('ZeroMatrix(5, 8)', '⎛0  0  0  0  0  0  0  0⎞'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎝0  0  0  0  0  0  0  0⎠');
  TestML('ZeroMatrix(5, 8) \ 12', '⎛0  0  0  0  0  0  0  0⎞'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎝0  0  0  0  0  0  0  0⎠');
  TestML('ZeroMatrix(5, 8) \ 8', '⎛0  0  0  0  0  0  0  0⎞'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎜0  0  0  0  0  0  0  0⎟'#13#10'⎝0  0  0  0  0  0  0  0⎠');
  TestML('ZeroMatrix(5, 8) \ 7', '⎛0  0  0  0  0  0  0  ⋯⎞'#13#10'⎜0  0  0  0  0  0  0  ⋯⎟'#13#10'⎜0  0  0  0  0  0  0  ⋯⎟'#13#10'⎜0  0  0  0  0  0  0  ⋯⎟'#13#10'⎝0  0  0  0  0  0  0  ⋯⎠');
  TestML('ZeroMatrix(5, 8) \ 4', '⎛0  0  0  0  ⋯⎞'#13#10'⎜0  0  0  0  ⋯⎟'#13#10'⎜0  0  0  0  ⋯⎟'#13#10'⎜0  0  0  0  ⋯⎟'#13#10'⎝⋮  ⋮  ⋮  ⋮  ⋱⎠');

  TestML('IdentityMatrix(1)', '(1)');
  TestML('IdentityMatrix(2)', '⎛1  0⎞'#13#10'⎝0  1⎠');
  TestML('IdentityMatrix(3)', '⎛1  0  0⎞'#13#10'⎜0  1  0⎟'#13#10'⎝0  0  1⎠');
  TestML('IdentityMatrix(4)', '⎛1  0  0  0⎞'#13#10'⎜0  1  0  0⎟'#13#10'⎜0  0  1  0⎟'#13#10'⎝0  0  0  1⎠');

  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2)', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 10', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 8', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 5', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 2', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 1', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  Test('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 0', 5, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);

  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2)', '⎛ 1   5   3   4   7⎞'#13#10'⎜ 6   5   4   3   8⎟'#13#10'⎜ 7   6   5   3  −2⎟'#13#10'⎝ 4   5   8  −9   2⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 10', '⎛ 1   5   3   4   7⎞'#13#10'⎜ 6   5   4   3   8⎟'#13#10'⎜ 7   6   5   3  −2⎟'#13#10'⎝ 4   5   8  −9   2⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 6', '⎛ 1   5   3   4   7⎞'#13#10'⎜ 6   5   4   3   8⎟'#13#10'⎜ 7   6   5   3  −2⎟'#13#10'⎝ 4   5   8  −9   2⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 5', '⎛ 1   5   3   4   7⎞'#13#10'⎜ 6   5   4   3   8⎟'#13#10'⎜ 7   6   5   3  −2⎟'#13#10'⎝ 4   5   8  −9   2⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 0', '⎛ 1   5   3   4   7⎞'#13#10'⎜ 6   5   4   3   8⎟'#13#10'⎜ 7   6   5   3  −2⎟'#13#10'⎝ 4   5   8  −9   2⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 4', '⎛ 1   5   3   4  ⋯ ⎞'#13#10'⎜ 6   5   4   3  ⋯ ⎟'#13#10'⎜ 7   6   5   3  ⋯ ⎟'#13#10'⎝ 4   5   8  −9  ⋯ ⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 3', '⎛1  5  3  ⋯⎞'#13#10'⎜6  5  4  ⋯⎟'#13#10'⎜7  6  5  ⋯⎟'#13#10'⎝⋮  ⋮  ⋮  ⋱⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 2', '⎛1  5  ⋯⎞'#13#10'⎜6  5  ⋯⎟'#13#10'⎝⋮  ⋮  ⋱⎠');
  TestML('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 1', '⎛1  ⋯⎞'#13#10'⎝⋮  ⋱⎠');

  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2)', '((1, 5, 3, 4, 7), (6, 5, 4, 3, 8), (7, 6, 5, 3, −2), (4, 5, 8, −9, 2))');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 10', '((1, 5, 3, 4, 7), (6, 5, 4, 3, 8), (7, 6, 5, 3, −2), (4, 5, 8, −9, 2))');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 6', '((1, 5, 3, 4, 7), (6, 5, 4, 3, 8), (7, 6, 5, 3, −2), (4, 5, 8, −9, 2))');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 5', '((1, 5, 3, 4, 7), (6, 5, 4, 3, 8), (7, 6, 5, 3, −2), (4, 5, 8, −9, 2))');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 0', '((1, 5, 3, 4, 7), (6, 5, 4, 3, 8), (7, 6, 5, 3, −2), (4, 5, 8, −9, 2))');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 4', '((1, 5, 3, 4, …), (6, 5, 4, 3, …), (7, 6, 5, 3, …), (4, 5, 8, −9, …))');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 3', '((1, 5, 3, …), (6, 5, 4, …), (7, 6, 5, …), …)');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 2', '((1, 5, …), (6, 5, …), …)');
  TestSL('matrix(5, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 1', '((1, …), …)');

  Test('matrix(2, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2)', 2, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  TestML('matrix(2, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 10', '⎛ 1   5⎞'#13#10'⎜ 3   4⎟'#13#10'⎜ 7   6⎟'#13#10'⎜ 5   4⎟'#13#10'⎜ 3   8⎟'#13#10'⎜ 7   6⎟'#13#10'⎜ 5   3⎟'#13#10'⎜−2   4⎟'#13#10'⎜ 5   8⎟'#13#10'⎝−9   2⎠');
  TestSL('matrix(2, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 10', '((1, 5), (3, 4), (7, 6), (5, 4), (3, 8), (7, 6), (5, 3), (−2, 4), (5, 8), (−9, 2))');
  TestML('matrix(2, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 5', '⎛1  5⎞'#13#10'⎜3  4⎟'#13#10'⎜7  6⎟'#13#10'⎜5  4⎟'#13#10'⎜3  8⎟'#13#10'⎝⋮  ⋮⎠');
  TestSL('matrix(2, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 5', '((1, 5), (3, 4), (7, 6), (5, 4), (3, 8), …)');

  Test('matrix(4, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2)', 4, [1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, -2, 4, 5, 8, -9, 2]);
  TestML('matrix(4, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2)', '⎛ 1   5   3   4⎞'#13#10'⎜ 7   6   5   4⎟'#13#10'⎜ 3   8   7   6⎟'#13#10'⎜ 5   3  −2   4⎟'#13#10'⎝ 5   8  −9   2⎠');
  TestML('matrix(4, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 3', '⎛1  5  3  ⋯⎞'#13#10'⎜7  6  5  ⋯⎟'#13#10'⎜3  8  7  ⋯⎟'#13#10'⎝⋮  ⋮  ⋮  ⋱⎠');
  TestSL('matrix(4, 1, 5, 3, 4, 7, 6, 5, 4, 3, 8, 7, 6, 5, 3, −2, 4, 5, 8, −9, 2) \ 3', '((1, 5, 3, …), (7, 6, 5, …), (3, 8, 7, …), …)');

  TestML('IdentityMatrix(3)/3', '⎛0.333333333333               0               0⎞'#13#10'⎜             0  0.333333333333               0⎟'#13#10'⎝             0               0  0.333333333333⎠');
  TestML('SetNumDigits(IdentityMatrix(3)/3, 10)', '⎛0.3333333333             0             0⎞'#13#10'⎜           0  0.3333333333             0⎟'#13#10'⎝           0             0  0.3333333333⎠');
  TestML('SetNumDigits(IdentityMatrix(3)/3, 4)', '⎛0.3333       0       0⎞'#13#10'⎜     0  0.3333       0⎟'#13#10'⎝     0       0  0.3333⎠');
  TestML('SetNumDigits(IdentityMatrix(3)/3, 4) \ 2', '⎛0.3333       0    ⋯   ⎞'#13#10'⎜     0  0.3333    ⋯   ⎟'#13#10'⎝  ⋮       ⋮       ⋱   ⎠');

  TestSL('IdentityMatrix(3)/3', '((0.333333333333, 0, 0), (0, 0.333333333333, 0), (0, 0, 0.333333333333))');
  TestSL('SetNumDigits(IdentityMatrix(3)/3, 10)', '((0.3333333333, 0, 0), (0, 0.3333333333, 0), (0, 0, 0.3333333333))');
  TestSL('SetNumDigits(IdentityMatrix(3)/3, 4)', '((0.3333, 0, 0), (0, 0.3333, 0), (0, 0, 0.3333))');
  TestSL('SetNumDigits(IdentityMatrix(3)/3, 4) \ 2', '((0.3333, 0, …), (0, 0.3333, …), …)');

  TestML('SetDigitGrouping(SetNumDigits(IdentityMatrix(3)/3, 6), 3)', '⎛0.333 333          0          0⎞'#13#10'⎜        0  0.333 333          0⎟'#13#10'⎝        0          0  0.333 333⎠');
  TestSL('SetDigitGrouping(SetNumDigits(IdentityMatrix(3)/3, 6), 3)', '((0.333 333, 0, 0), (0, 0.333 333, 0), (0, 0, 0.333 333))');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[3]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[4]', 40.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[5]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[6]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[7]', failure, 'Index 7 out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-3]', 40.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-4]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-5]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-6]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-7]', failure, 'Index -7 out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[0]', failure, 'Index 0 out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 0]', failure, 'Index (1, 0) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 1]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 2]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 3]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 4]', failure, 'Index (1, 4) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 1]', 40.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 2]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 3]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 4]', failure, 'Index (2, 4) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[3, 1]', failure, 'Index (3, 1) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, -1]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, -2]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, -3]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, -4]', failure, 'Index (1, -4) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, 1]', 40.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, 2]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, 3]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, 4]', failure, 'Index (-1, 4) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2, 1]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2, 2]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2, 3]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2, 4]', failure, 'Index (-2, 4) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, 0]', failure, 'Index (-1, 0) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, -1]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, -2]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2, -1]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-2, -2]', 20.0);

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 0)]', failure, 'Index (1, 0) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 1)]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 2)]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 3)]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 4)]', failure, 'Index (1, 4) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 1)]', 40.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 2)]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 3)]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 4)]', failure, 'Index (2, 4) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(3, 1)]', failure, 'Index (3, 1) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, -1)]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, -2)]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, -3)]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, -4)]', failure, 'Index (1, -4) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 1)]', 40.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 2)]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 3)]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 4)]', failure, 'Index (-1, 4) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 1)]', 10.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 2)]', 20.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 3)]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 4)]', failure, 'Index (-2, 4) out of bounds.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 0)]', failure, 'Index (-1, 0) out of bounds.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, -1)]', 60.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, -2)]', 50.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-2, -1)]', 30.0);
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-2, -2)]', 20.0);

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[6] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[7] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[0] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-20] ≔ 100', failure, 'Left side cannot be assigned to.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 2] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, 5] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[1, -1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 2] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 100] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, -4] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[2, 0] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[-1, 1] ≔ 100', failure, 'Left side cannot be assigned to.');

  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 1)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 2)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, 5)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(1, -1)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 2)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 100)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, -4)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(2, 0)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨10, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 1)] ≔ 100', failure, 'Left side cannot be assigned to.');


  //
  // Complex matrices
  //

  Test('❨❨i, 2❩, ❨3, 4❩❩', 2, [ImaginaryUnit, 2, 3, 4]);
  Test('matrix(2, i, 2, 3, 4)', 2, [ImaginaryUnit, 2, 3, 4]);
  Test('❨❨i❩, ❨2❩, ❨3❩, ❨4❩❩', 1, [ImaginaryUnit, 2, 3, 4]);
  Test('❨❨i, 2, 3, 4❩❩', 4, [ImaginaryUnit, 2, 3, 4]);
  Test('❨❨i, 2❩, ❨3, 4, 5❩❩', failure, 'Attempt to create a non-rectangular matrix.');
  Test('❨❨i, 2❩, ❨3, 4❩❩ + ❨❨1, 0❩, ❨0, i❩❩', 2, [1+ImaginaryUnit, 2, 3, 4+ImaginaryUnit]);
  TestML('❨❨i, 2❩, ❨3, 4❩❩ + ❨❨1, 0❩, ❨0, i❩❩', '⎛1 + i      2⎞'#13#10'⎝    3  4 + i⎠');
  TestSL('❨❨i, 2❩, ❨3, 4❩❩ + ❨❨1, 0❩, ❨0, i❩❩', '((1 + i, 2), (3, 4 + i))');

  TestML('i⋅IdentityMatrix(1)', '(i)');
  TestML('i⋅IdentityMatrix(2)', '⎛i  0⎞'#13#10'⎝0  i⎠');
  TestML('i⋅IdentityMatrix(3)', '⎛i  0  0⎞'#13#10'⎜0  i  0⎟'#13#10'⎝0  0  i⎠');
  TestML('i⋅IdentityMatrix(4)', '⎛i  0  0  0⎞'#13#10'⎜0  i  0  0⎟'#13#10'⎜0  0  i  0⎟'#13#10'⎝0  0  0  i⎠');

  Test('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3)', 5, [3, ImaginaryUnit, 5, 7, ImaginaryUnit, 2, ImaginaryUnit, 3, 4, 5, 1, ImaginaryUnit, ImaginaryUnit, 2, 3]);
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3)', '⎛3  i  5  7  i⎞'#13#10'⎜2  i  3  4  5⎟'#13#10'⎝1  i  i  2  3⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 0', '⎛3  i  5  7  i⎞'#13#10'⎜2  i  3  4  5⎟'#13#10'⎝1  i  i  2  3⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 10', '⎛3  i  5  7  i⎞'#13#10'⎜2  i  3  4  5⎟'#13#10'⎝1  i  i  2  3⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 5', '⎛3  i  5  7  i⎞'#13#10'⎜2  i  3  4  5⎟'#13#10'⎝1  i  i  2  3⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 4', '⎛3  i  5  7  ⋯⎞'#13#10'⎜2  i  3  4  ⋯⎟'#13#10'⎝1  i  i  2  ⋯⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 3', '⎛3  i  5  ⋯⎞'#13#10'⎜2  i  3  ⋯⎟'#13#10'⎝1  i  i  ⋯⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 2', '⎛3  i  ⋯⎞'#13#10'⎜2  i  ⋯⎟'#13#10'⎝⋮  ⋮  ⋱⎠');
  TestML('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 1', '⎛3  ⋯⎞'#13#10'⎝⋮  ⋱⎠');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3)', '((3, i, 5, 7, i), (2, i, 3, 4, 5), (1, i, i, 2, 3))');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 0', '((3, i, 5, 7, i), (2, i, 3, 4, 5), (1, i, i, 2, 3))');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 10', '((3, i, 5, 7, i), (2, i, 3, 4, 5), (1, i, i, 2, 3))');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 5', '((3, i, 5, 7, i), (2, i, 3, 4, 5), (1, i, i, 2, 3))');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 4', '((3, i, 5, 7, …), (2, i, 3, 4, …), (1, i, i, 2, …))');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 3', '((3, i, 5, …), (2, i, 3, …), (1, i, i, …))');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 2', '((3, i, …), (2, i, …), …)');
  TestSL('matrix(5, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \ 1', '((3, …), …)');

  Test('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3)', 3, [3, ImaginaryUnit, 5, 7, ImaginaryUnit, 2, ImaginaryUnit, 3, 4, 5, 1, ImaginaryUnit, ImaginaryUnit, 2, 3]);
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3)', '⎛3  i  5⎞'#13#10'⎜7  i  2⎟'#13#10'⎜i  3  4⎟'#13#10'⎜5  1  i⎟'#13#10'⎝i  2  3⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \0', '⎛3  i  5⎞'#13#10'⎜7  i  2⎟'#13#10'⎜i  3  4⎟'#13#10'⎜5  1  i⎟'#13#10'⎝i  2  3⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \10', '⎛3  i  5⎞'#13#10'⎜7  i  2⎟'#13#10'⎜i  3  4⎟'#13#10'⎜5  1  i⎟'#13#10'⎝i  2  3⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \5', '⎛3  i  5⎞'#13#10'⎜7  i  2⎟'#13#10'⎜i  3  4⎟'#13#10'⎜5  1  i⎟'#13#10'⎝i  2  3⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \4', '⎛3  i  5⎞'#13#10'⎜7  i  2⎟'#13#10'⎜i  3  4⎟'#13#10'⎜5  1  i⎟'#13#10'⎝⋮  ⋮  ⋮⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \3', '⎛3  i  5⎞'#13#10'⎜7  i  2⎟'#13#10'⎜i  3  4⎟'#13#10'⎝⋮  ⋮  ⋮⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \2', '⎛3  i  ⋯⎞'#13#10'⎜7  i  ⋯⎟'#13#10'⎝⋮  ⋮  ⋱⎠');
  TestML('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \1', '⎛3  ⋯⎞'#13#10'⎝⋮  ⋱⎠');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3)', '((3, i, 5), (7, i, 2), (i, 3, 4), (5, 1, i), (i, 2, 3))');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \0', '((3, i, 5), (7, i, 2), (i, 3, 4), (5, 1, i), (i, 2, 3))');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \10', '((3, i, 5), (7, i, 2), (i, 3, 4), (5, 1, i), (i, 2, 3))');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \5', '((3, i, 5), (7, i, 2), (i, 3, 4), (5, 1, i), (i, 2, 3))');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \4', '((3, i, 5), (7, i, 2), (i, 3, 4), (5, 1, i), …)');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \3', '((3, i, 5), (7, i, 2), (i, 3, 4), …)');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \2', '((3, i, …), (7, i, …), …)');
  TestSL('matrix(3, 3, i, 5, 7, i, 2, i, 3, 4, 5, 1, i, i, 2, 3) \1', '((3, …), …)');

  TestML('❨❨1/3, i/3❩, ❨1/2, 1/4❩❩', '⎛  0.333333333333  0.333333333333⋅i⎞'#13#10'⎝             0.5              0.25⎠');
  TestML('SetNumDigits(❨❨1/3, i/3❩, ❨1/2, 1/4❩❩, 4)', '⎛  0.3333  0.3333⋅i⎞'#13#10'⎝     0.5      0.25⎠');
  TestML('SetNumDigits(❨❨1/3, i/3❩, ❨1/2, 1/4❩❩, 4) \ 1', '⎛0.3333    ⋯   ⎞'#13#10'⎝  ⋮       ⋱   ⎠');
  TestSL('❨❨1/3, i/3❩, ❨1/2, 1/4❩❩', '((0.333333333333, 0.333333333333⋅i), (0.5, 0.25))');
  TestSL('SetNumDigits(❨❨1/3, i/3❩, ❨1/2, 1/4❩❩, 4)', '((0.3333, 0.3333⋅i), (0.5, 0.25))');
  TestSL('SetNumDigits(❨❨1/3, i/3❩, ❨1/2, 1/4❩❩, 4) \ 1', '((0.3333, …), …)');

  Test('❨❨1, 2❩, ❨3, 4❩❩ + ❨❨i, 0❩, ❨0, i❩❩', 2, [1+ImaginaryUnit, 2, 3, 4+ImaginaryUnit]);
  Test('❨❨i, −i❩, ❨−i, i❩❩ + IdentityMatrix(2)', 2, [1+ImaginaryUnit, -ImaginaryUnit, -ImaginaryUnit, 1+ImaginaryUnit]);

  TestML('SetDigitGrouping(❨❨12345, 12345⋅i❩❩, 3)', '(  12 345  12 345⋅i)');
  TestSL('SetDigitGrouping(❨❨12345, 12345⋅i❩❩, 3)', '((12 345, 12 345⋅i))');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[3]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[4]', TASC(40.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[5]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[6]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[7]', failure, 'Index 7 out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-3]', TASC(40.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-4]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-5]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-6]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-7]', failure, 'Index -7 out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[0]', failure, 'Index 0 out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 0]', failure, 'Index (1, 0) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 1]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 2]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 3]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 4]', failure, 'Index (1, 4) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 1]', TASC(40.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 2]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 3]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 4]', failure, 'Index (2, 4) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[3, 1]', failure, 'Index (3, 1) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, -1]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, -2]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, -3]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, -4]', failure, 'Index (1, -4) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, 1]', TASC(40.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, 2]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, 3]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, 4]', failure, 'Index (-1, 4) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2, 1]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2, 2]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2, 3]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2, 4]', failure, 'Index (-2, 4) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, 0]', failure, 'Index (-1, 0) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, -1]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, -2]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2, -1]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-2, -2]', TASC(20.0));

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 0)]', failure, 'Index (1, 0) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 1)]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 2)]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 3)]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 4)]', failure, 'Index (1, 4) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 1)]', TASC(40.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 2)]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 3)]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 4)]', failure, 'Index (2, 4) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(3, 1)]', failure, 'Index (3, 1) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, -1)]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, -2)]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, -3)]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, -4)]', failure, 'Index (1, -4) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 1)]', TASC(40.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 2)]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 3)]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 4)]', failure, 'Index (-1, 4) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 1)]', ImaginaryUnit);
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 2)]', TASC(20.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 3)]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-2, 4)]', failure, 'Index (-2, 4) out of bounds.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 0)]', failure, 'Index (-1, 0) out of bounds.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, -1)]', TASC(60.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, -2)]', TASC(50.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-2, -1)]', TASC(30.0));
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-2, -2)]', TASC(20.0));

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[6] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[7] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[0] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-20] ≔ 100', failure, 'Left side cannot be assigned to.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 2] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, 5] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[1, -1] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 2] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 100] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, -4] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[2, 0] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[-1, 1] ≔ 100', failure, 'Left side cannot be assigned to.');

  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 1)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 2)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, 5)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(1, -1)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 2)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 100)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, -4)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(2, 0)] ≔ 100', failure, 'Left side cannot be assigned to.');
  Test('❨❨i, 20, 30❩, ❨40, 50, 60❩❩[''(-1, 1)] ≔ 100', failure, 'Left side cannot be assigned to.');


  //
  // Colours
  //

  Test('color("red")', TRGB(clRed), True, 'rgba(1.000, 0.000, 0.000, 1.000)');
  Test('color("lime")', TRGB(clLime), True, 'rgba(0.000, 1.000, 0.000, 1.000)');
  Test('color("blue")', TRGB(clBlue), True, 'rgba(0.000, 0.000, 1.000, 1.000)');
  Test('color("white")', TRGB(clWhite), True, 'rgba(1.000, 1.000, 1.000, 1.000)');
  Test('color("black")', TRGB(clBlack), True, 'rgba(0.000, 0.000, 0.000, 1.000)');
  Test('color("yellow")', TRGB(clYellow), True, 'rgba(1.000, 1.000, 0.000, 1.000)');
  Test('color("aqua")', TRGB(clAqua), True, 'rgba(0.000, 1.000, 1.000, 1.000)');
  Test('color("fuchsia")', TRGB(clFuchsia), True, 'rgba(1.000, 0.000, 1.000, 1.000)');
  Test('rgb(0.2, 0.3, 0.4)', TRGB.Create(0.2, 0.3, 0.4), True, 'rgba(0.200, 0.300, 0.400, 1.000)');
  TestML('GetRGB(rgb(1/3, 1/7, 1/9)) @ (x ↦ SetNumDigits(x, 4))', 'red: 0.3333'#13#10'green: 0.1429'#13#10'blue: 0.1111');
  TestSL('GetRGB(rgb(1/3, 1/7, 1/9)) @ (x ↦ SetNumDigits(x, 4))', '(red: 0.3333, green: 0.1429, blue: 0.1111)');


  //
  // Lists
  //

  Test('''(1, 2, "cat", ❨1, 0❩)',
    TAlgosimArray.CreateWithValue(
      [ASOInt(1), ASOInt(2), ASO('cat'), ASO(ASR2(1, 0))]
    )
  );

  Test('''(1, 2, "cat", ❨1, 0❩)[1]', 1);
  Test('''(1, 2, "cat", ❨1, 0❩)[2]', 2);
  Test('''(1, 2, "cat", ❨1, 0❩)[3]', 'cat');
  Test('''(1, 2, "cat", ❨1, 0❩)[4]', ASO(ASR2(1, 0)));
  Test('''(1, 2, "cat", ❨1, 0❩)[5]', failure, 'Index 5 out of bounds.');

  Test('''(1, 2, "cat", ❨1, 0❩)[-1]', ASO(ASR2(1, 0)));
  Test('''(1, 2, "cat", ❨1, 0❩)[-2]', 'cat');
  Test('''(1, 2, "cat", ❨1, 0❩)[-3]', 2);
  Test('''(1, 2, "cat", ❨1, 0❩)[-4]', 1);
  Test('''(1, 2, "cat", ❨1, 0❩)[-5]', failure, 'Index -5 out of bounds.');

  Test('''(1, 2, "cat", ❨1, 0❩)[0]', failure, 'Index 0 out of bounds.');

  TestML('''(1, 2, 3)', '1'#13#10'2'#13#10'3');
  TestSL('''(1, 2, 3)', '(1, 2, 3)');

  TestML('''(123)', '123');
  TestSL('''(123)', '(123)');

  TestML('''(1/3, 1/7, 1/9)', '0.333333333333'#13#10'0.142857142857'#13#10'0.111111111111');
  TestML('''(1/3, 1/7, 1/9) @ RealNumber', '0.333333333333'#13#10'0.142857142857'#13#10'0.111111111111');
  TestML('''(1/3, 1/7, 1/9) @ RealNumber @ (x ↦ SetNumDigits(x, 4))', '0.3333'#13#10'0.1429'#13#10'0.1111');
  TestML('''(1/3, 1/7, 1/9) @ ToFraction', '1/3'#13#10'1/7'#13#10'1/9');

  TestSL('''(1/3, 1/7, 1/9)', '(0.333333333333, 0.142857142857, 0.111111111111)');
  TestSL('''(1/3, 1/7, 1/9) @ RealNumber', '(0.333333333333, 0.142857142857, 0.111111111111)');
  TestSL('''(1/3, 1/7, 1/9) @ RealNumber @ (x ↦ SetNumDigits(x, 4))', '(0.3333, 0.1429, 0.1111)');
  TestSL('''(1/3, 1/7, 1/9) @ ToFraction', '(1/3, 1/7, 1/9)');

  TestML('SequenceList(100)', '1'#13#10'2'#13#10'3'#13#10'4'#13#10'5'#13#10'6'#13#10'7'#13#10'8'#13#10'9'#13#10'10'#13#10'11'#13#10'12'#13#10'13'#13#10'14'#13#10'15'#13#10'16'
    +#13#10'17'#13#10'18'#13#10'19'#13#10'20'#13#10'21'#13#10'22'#13#10'23'#13#10'24'+#13#10'25'#13#10'26'#13#10'27'#13#10'28'#13#10'29'#13#10'30'#13#10'31'#13#10'32'#13#10'33'#13#10'34'#13#10'35'+#13#10'36'#13#10'37'#13#10'38'#13#10'39'#13#10'40'#13#10'41'#13#10'42'#13#10'43'#13#10'44'#13#10'45'#13#10'46'+#13#10'47'#13#10'48'#13#10'49'#13#10'50'#13#10'51'#13#10'52'#13#10'53'#13#10'54'#13#10'55'#13#10'56'
    +#13#10'57'#13#10'58'#13#10'59'#13#10'60'#13#10'61'#13#10'62'#13#10'63'#13#10'64'#13#10'65'#13#10'66'#13#10'67'#13#10'68'
    +#13#10'69'#13#10'70'#13#10'71'#13#10'72'#13#10'73'#13#10'74'#13#10'75'#13#10'76'#13#10'77'#13#10'78'#13#10'79'#13#10'80'#13#10'81'#13#10'82'#13#10'83'#13#10'84'#13#10'85'#13#10'86'#13#10'87'#13#10'88'#13#10'89'#13#10'90'#13#10'91'#13#10'92'#13#10'93'#13#10'94'#13#10'95'#13#10'96'#13#10'97'#13#10'98'#13#10'99'#13#10'100');
  TestSL('SequenceList(100)', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, '+'21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, '+'46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)');

  TestML('SequenceList(200)', '1'#13#10'2'#13#10'3'#13#10'4'#13#10'5'#13#10'6'#13#10'7'#13#10'8'#13#10'9'#13#10'10'#13#10'11'#13#10'12'#13#10'13'#13#10'14'#13#10'15'#13#10'16'
    +#13#10'17'#13#10'18'#13#10'19'#13#10'20'#13#10'21'#13#10'22'#13#10'23'#13#10'24'
    +#13#10'25'#13#10'26'#13#10'27'#13#10'28'#13#10'29'#13#10'30'#13#10'31'#13#10'32'#13#10'33'#13#10'34'#13#10'35'
    +#13#10'36'#13#10'37'#13#10'38'#13#10'39'#13#10'40'#13#10'41'#13#10'42'#13#10'43'#13#10'44'#13#10'45'#13#10'46'
    +#13#10'47'#13#10'48'#13#10'49'#13#10'50'#13#10'51'#13#10'52'#13#10'53'#13#10'54'#13#10'55'#13#10'56'
    +#13#10'57'#13#10'58'#13#10'59'#13#10'60'#13#10'61'#13#10'62'#13#10'63'#13#10'64'#13#10'65'#13#10'66'#13#10'67'#13#10'68'
    +#13#10'69'#13#10'70'#13#10'71'#13#10'72'#13#10'73'#13#10'74'#13#10'75'#13#10'76'#13#10'77'#13#10'78'#13#10'79'#13#10'80'#13#10'81'#13#10'82'#13#10'83'#13#10'84'#13#10'85'#13#10'86'#13#10'87'#13#10'88'#13#10'89'#13#10'90'#13#10'91'#13#10'92'#13#10'93'#13#10'94'#13#10'95'#13#10'96'#13#10'97'#13#10'98'#13#10'99'#13#10'100'#13#10'⋮');
  TestSL('SequenceList(200)', '(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, '+'21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, '+'46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, …)');

  TestML('''(1, 2, 3, 4, 5) \ 0', '1'#13#10'2'#13#10'3'#13#10'4'#13#10'5');
  TestML('''(1, 2, 3, 4, 5) \ 10', '1'#13#10'2'#13#10'3'#13#10'4'#13#10'5');
  TestML('''(1, 2, 3, 4, 5) \ 5', '1'#13#10'2'#13#10'3'#13#10'4'#13#10'5');
  TestML('''(1, 2, 3, 4, 5) \ 4', '1'#13#10'2'#13#10'3'#13#10'4'#13#10'⋮');
  TestML('''(1, 2, 3, 4, 5) \ 3', '1'#13#10'2'#13#10'3'#13#10'⋮');
  TestML('''(1, 2, 3, 4, 5) \ 2', '1'#13#10'2'#13#10'⋮');
  TestML('''(1, 2, 3, 4, 5) \ 1', '1'#13#10'⋮');

  TestSL('''(1, 2, 3, 4, 5) \ 0', '(1, 2, 3, 4, 5)');
  TestSL('''(1, 2, 3, 4, 5) \ 10', '(1, 2, 3, 4, 5)');
  TestSL('''(1, 2, 3, 4, 5) \ 5', '(1, 2, 3, 4, 5)');
  TestSL('''(1, 2, 3, 4, 5) \ 4', '(1, 2, 3, 4, …)');
  TestSL('''(1, 2, 3, 4, 5) \ 3', '(1, 2, 3, …)');
  TestSL('''(1, 2, 3, 4, 5) \ 2', '(1, 2, …)');
  TestSL('''(1, 2, 3, 4, 5) \ 1', '(1, …)');

  TestML('''()', '');
  TestSL('''()',