deterministic creation sequence id for operations (#448)

This commit is contained in:
Pantazis Deligiannis 2023-01-26 13:41:25 -08:00 коммит произвёл GitHub
Родитель ac0e8d1025
Коммит e50bd3b46a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 703 добавлений и 503 удалений

Просмотреть файл

@ -307,7 +307,7 @@ namespace Microsoft.Coyote.Actors
else else
{ {
string[] eventNameArray = new string[eventTypes.Length - 1]; string[] eventNameArray = new string[eventTypes.Length - 1];
for (int i = 0; i < eventTypes.Length - 2; i++) for (int i = 0; i < eventTypes.Length - 2; ++i)
{ {
eventNameArray[i] = eventTypes[i].FullName; eventNameArray[i] = eventTypes[i].FullName;
} }

Просмотреть файл

@ -53,12 +53,23 @@ namespace Microsoft.Coyote.Coverage
[DataMember] [DataMember]
public Dictionary<string, Dictionary<string, long>> SchedulingPointStackTraces { get; private set; } public Dictionary<string, Dictionary<string, long>> SchedulingPointStackTraces { get; private set; }
/// <summary>
/// Set of explored paths represented as ordered operations identified by their creation sequence ids.
/// </summary>
[DataMember]
public HashSet<string> ExploredPaths { get; private set; }
/// <summary> /// <summary>
/// Set of visited program states represented as hashes. /// Set of visited program states represented as hashes.
/// </summary> /// </summary>
[DataMember] [DataMember]
public HashSet<int> VisitedStates { get; private set; } public HashSet<int> VisitedStates { get; private set; }
/// <summary>
/// Set of encountered operation creation sequence ids.
/// </summary>
public HashSet<ulong> OperationSequenceIds { get; private set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CoverageInfo"/> class. /// Initializes a new instance of the <see cref="CoverageInfo"/> class.
/// </summary> /// </summary>
@ -68,7 +79,9 @@ namespace Microsoft.Coyote.Coverage
this.MonitorsToStates = new Dictionary<string, HashSet<string>>(); this.MonitorsToStates = new Dictionary<string, HashSet<string>>();
this.RegisteredMonitorEvents = new Dictionary<string, HashSet<string>>(); this.RegisteredMonitorEvents = new Dictionary<string, HashSet<string>>();
this.SchedulingPointStackTraces = new Dictionary<string, Dictionary<string, long>>(); this.SchedulingPointStackTraces = new Dictionary<string, Dictionary<string, long>>();
this.ExploredPaths = new HashSet<string>();
this.VisitedStates = new HashSet<int>(); this.VisitedStates = new HashSet<int>();
this.OperationSequenceIds = new HashSet<ulong>();
} }
/// <summary> /// <summary>
@ -141,11 +154,21 @@ namespace Microsoft.Coyote.Coverage
} }
} }
/// <summary>
/// Declares a new explored execution path.
/// </summary>
internal void DeclareExploredExecutionPath(string path) => this.ExploredPaths.Add(path);
/// <summary> /// <summary>
/// Declares a new visited state. /// Declares a new visited state.
/// </summary> /// </summary>
internal void DeclareVisitedState(int state) => this.VisitedStates.Add(state); internal void DeclareVisitedState(int state) => this.VisitedStates.Add(state);
/// <summary>
/// Declares a new operation creation sequence id.
/// </summary>
internal void DeclareOperationSequenceId(ulong sequenceId) => this.OperationSequenceIds.Add(sequenceId);
/// <summary> /// <summary>
/// Loads the coverage info XML file into a <see cref="CoverageInfo"/> object of the specified type. /// Loads the coverage info XML file into a <see cref="CoverageInfo"/> object of the specified type.
/// </summary> /// </summary>
@ -246,7 +269,9 @@ namespace Microsoft.Coyote.Coverage
} }
} }
this.ExploredPaths.UnionWith(coverageInfo.ExploredPaths);
this.VisitedStates.UnionWith(coverageInfo.VisitedStates); this.VisitedStates.UnionWith(coverageInfo.VisitedStates);
this.OperationSequenceIds.UnionWith(coverageInfo.OperationSequenceIds);
} }
} }
} }

Просмотреть файл

@ -678,8 +678,11 @@ namespace Microsoft.Coyote.Runtime
this.PendingStartOperationMap.Add(op, new ManualResetEventSlim(false)); this.PendingStartOperationMap.Add(op, new ManualResetEventSlim(false));
} }
this.LogWriter.LogDebug("[coyote::debug] Created operation '{0}' of group '{1}' on thread '{2}'.", // Register the operation creation sequence id for coverage.
op.Name, op.Group, Thread.CurrentThread.ManagedThreadId); this.CoverageInfo.DeclareOperationSequenceId(op.SequenceId);
this.LogWriter.LogDebug("[coyote::debug] Created operation {0} on thread '{1}'.",
op.DebugInfo, Thread.CurrentThread.ManagedThreadId);
} }
} }
@ -697,8 +700,8 @@ namespace Microsoft.Coyote.Runtime
this.SetCurrentExecutionContext(op); this.SetCurrentExecutionContext(op);
using (SynchronizedSection.Enter(this.RuntimeLock)) using (SynchronizedSection.Enter(this.RuntimeLock))
{ {
this.LogWriter.LogDebug("[coyote::debug] Started operation '{0}' of group '{1}' on thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Started operation {0} on thread '{1}'.",
op.Name, op.Group, Thread.CurrentThread.ManagedThreadId); op.DebugInfo, Thread.CurrentThread.ManagedThreadId);
op.Status = OperationStatus.Enabled; op.Status = OperationStatus.Enabled;
if (this.SchedulingPolicy is SchedulingPolicy.Interleaving) if (this.SchedulingPolicy is SchedulingPolicy.Interleaving)
{ {
@ -733,8 +736,8 @@ namespace Microsoft.Coyote.Runtime
var pendingOp = this.PendingStartOperationMap.First(); var pendingOp = this.PendingStartOperationMap.First();
while (pendingOp.Key.Status is OperationStatus.None) while (pendingOp.Key.Status is OperationStatus.None)
{ {
this.LogWriter.LogDebug("[coyote::debug] Sleeping thread '{0}' until operation '{1}' of group '{2}' starts.", this.LogWriter.LogDebug("[coyote::debug] Sleeping thread '{0}' until operation {1} starts.",
Thread.CurrentThread.ManagedThreadId, pendingOp.Key.Name, pendingOp.Key.Group); Thread.CurrentThread.ManagedThreadId, pendingOp.Key.DebugInfo);
using (SynchronizedSection.Exit(this.RuntimeLock)) using (SynchronizedSection.Exit(this.RuntimeLock))
{ {
try try
@ -771,15 +774,15 @@ namespace Microsoft.Coyote.Runtime
// Do not allow the operation to wake up, unless its currently scheduled and enabled or the runtime stopped running. // Do not allow the operation to wake up, unless its currently scheduled and enabled or the runtime stopped running.
while (!(op == this.ScheduledOperation && op.Status is OperationStatus.Enabled) && this.ExecutionStatus is ExecutionStatus.Running) while (!(op == this.ScheduledOperation && op.Status is OperationStatus.Enabled) && this.ExecutionStatus is ExecutionStatus.Running)
{ {
this.LogWriter.LogDebug("[coyote::debug] Sleeping operation '{0}' of group '{1}' on thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Sleeping operation {0} on thread '{1}'.",
op.Name, op.Group, Thread.CurrentThread.ManagedThreadId); op.DebugInfo, Thread.CurrentThread.ManagedThreadId);
using (SynchronizedSection.Exit(this.RuntimeLock)) using (SynchronizedSection.Exit(this.RuntimeLock))
{ {
op.WaitSignal(); op.WaitSignal();
} }
this.LogWriter.LogDebug("[coyote::debug] Waking up operation '{0}' of group '{1}' on thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Waking up operation {0} on thread '{1}'.",
op.Name, op.Group, Thread.CurrentThread.ManagedThreadId); op.DebugInfo, Thread.CurrentThread.ManagedThreadId);
} }
} }
} }
@ -798,8 +801,8 @@ namespace Microsoft.Coyote.Runtime
current ??= this.GetExecutingOperation(); current ??= this.GetExecutingOperation();
while (current != null && !condition() && this.ExecutionStatus is ExecutionStatus.Running) while (current != null && !condition() && this.ExecutionStatus is ExecutionStatus.Running)
{ {
this.LogWriter.LogDebug("[coyote::debug] Operation '{0}' of group '{1}' is waiting for {2} on thread '{3}'.", this.LogWriter.LogDebug("[coyote::debug] Operation {0} is waiting for {1} on thread '{2}'.",
current.Name, current.Group, debugMsg ?? "condition to get resolved", Thread.CurrentThread.ManagedThreadId); current.DebugInfo, debugMsg ?? "condition to get resolved", Thread.CurrentThread.ManagedThreadId);
// TODO: can we identify when the dependency is uncontrolled? // TODO: can we identify when the dependency is uncontrolled?
current.PauseWithDependency(condition, isConditionControlled); current.PauseWithDependency(condition, isConditionControlled);
this.ScheduleNextOperation(current, SchedulingPointType.Pause); this.ScheduleNextOperation(current, SchedulingPointType.Pause);
@ -862,8 +865,8 @@ namespace Microsoft.Coyote.Runtime
// now been resolved, so resume it on this uncontrolled thread. // now been resolved, so resume it on this uncontrolled thread.
current = this.ScheduledOperation; current = this.ScheduledOperation;
type = this.LastPostponedSchedulingPoint.Value; type = this.LastPostponedSchedulingPoint.Value;
this.LogWriter.LogDebug("[coyote::debug] Resuming scheduling point '{0}' of operation '{1}' in uncontrolled thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Resuming scheduling point '{0}' of operation {1} in uncontrolled thread '{2}'.",
type, current, Thread.CurrentThread.ManagedThreadId); type, current.DebugInfo, Thread.CurrentThread.ManagedThreadId);
} }
else if (type is SchedulingPointType.Create || type is SchedulingPointType.ContinueWith) else if (type is SchedulingPointType.Create || type is SchedulingPointType.ContinueWith)
{ {
@ -899,14 +902,14 @@ namespace Microsoft.Coyote.Runtime
isSuppressible && current.Status is OperationStatus.Enabled) isSuppressible && current.Status is OperationStatus.Enabled)
{ {
// Suppress the scheduling point. // Suppress the scheduling point.
this.LogWriter.LogDebug("[coyote::debug] Operation '{0}' of group '{1}' suppressed scheduling point '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Operation {0} suppressed scheduling point '{1}'.",
current.Name, current.Group, type); current.DebugInfo, type);
return false; return false;
} }
this.LogWriter.LogDebug( this.LogWriter.LogDebug(
"[coyote::debug] Operation '{0}' of group '{1}' reached scheduling point '{2}' at execution step '{3}' on thread '{4}'.", "[coyote::debug] Operation {0} reached scheduling point '{1}' at execution step '{2}' on thread '{3}'.",
current.Name, current.Group, type, this.Scheduler.StepCount, Thread.CurrentThread.ManagedThreadId); current.DebugInfo, type, this.Scheduler.StepCount, Thread.CurrentThread.ManagedThreadId);
this.Assert(!this.IsSpecificationInvoked, "Executing a specification monitor must be atomic."); this.Assert(!this.IsSpecificationInvoked, "Executing a specification monitor must be atomic.");
// Checks if the scheduling steps bound has been reached. // Checks if the scheduling steps bound has been reached.
@ -931,8 +934,8 @@ namespace Microsoft.Coyote.Runtime
// If uncontrolled concurrency is detected, then do not check for deadlocks directly, // If uncontrolled concurrency is detected, then do not check for deadlocks directly,
// but instead leave it to the background deadlock detection timer and postpone the // but instead leave it to the background deadlock detection timer and postpone the
// scheduling point, which might get resolved from an uncontrolled thread. // scheduling point, which might get resolved from an uncontrolled thread.
this.LogWriter.LogDebug("[coyote::debug] Postponing scheduling point '{0}' of operation '{1}' due to potential deadlock.", this.LogWriter.LogDebug("[coyote::debug] Postponing scheduling point '{0}' of operation {1} due to potential deadlock.",
type, current); type, current.DebugInfo);
this.LastPostponedSchedulingPoint = type; this.LastPostponedSchedulingPoint = type;
this.PauseOperation(current); this.PauseOperation(current);
return false; return false;
@ -960,8 +963,8 @@ namespace Microsoft.Coyote.Runtime
return false; return false;
} }
this.LogWriter.LogDebug("[coyote::debug] Scheduling operation '{0}' of group '{1}' from thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Scheduling operation {0} from thread '{1}'.",
next.Name, next.Group, Thread.CurrentThread.ManagedThreadId); next.DebugInfo, Thread.CurrentThread.ManagedThreadId);
bool isNextOperationScheduled = current != next; bool isNextOperationScheduled = current != next;
if (isNextOperationScheduled) if (isNextOperationScheduled)
{ {
@ -1001,8 +1004,8 @@ namespace Microsoft.Coyote.Runtime
{ {
// Choose the next delay to inject. The value is in milliseconds. // Choose the next delay to inject. The value is in milliseconds.
int delay = this.GetNondeterministicDelay(current, (int)this.Configuration.MaxFuzzingDelay); int delay = this.GetNondeterministicDelay(current, (int)this.Configuration.MaxFuzzingDelay);
this.LogWriter.LogDebug("[coyote::debug] Delaying operation '{0}' on thread '{1}' by {2}ms.", this.LogWriter.LogDebug("[coyote::debug] Delaying operation {0} on thread '{1}' by {2}ms.",
current.Name, Thread.CurrentThread.ManagedThreadId, delay); current.DebugInfo, Thread.CurrentThread.ManagedThreadId, delay);
// Only sleep the executing operation if a non-zero delay was chosen. // Only sleep the executing operation if a non-zero delay was chosen.
if (delay > 0) if (delay > 0)
@ -1028,8 +1031,8 @@ namespace Microsoft.Coyote.Runtime
op.ExecuteContinuations(); op.ExecuteContinuations();
using (SynchronizedSection.Enter(this.RuntimeLock)) using (SynchronizedSection.Enter(this.RuntimeLock))
{ {
this.LogWriter.LogDebug("[coyote::debug] Completed operation '{0}' of group '{1}' on thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Completed operation {0} on thread '{1}'.",
op.Name, op.Group, Thread.CurrentThread.ManagedThreadId); op.DebugInfo, Thread.CurrentThread.ManagedThreadId);
op.Status = OperationStatus.Completed; op.Status = OperationStatus.Completed;
} }
} }
@ -1045,8 +1048,8 @@ namespace Microsoft.Coyote.Runtime
{ {
if (op.Status is OperationStatus.Completed) if (op.Status is OperationStatus.Completed)
{ {
this.LogWriter.LogDebug("[coyote::debug] Resetting operation '{0}' of group '{1}' from thread '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Resetting operation {0} from thread '{1}'.",
op.Name, op.Group, Thread.CurrentThread.ManagedThreadId); op.DebugInfo, Thread.CurrentThread.ManagedThreadId);
op.Status = OperationStatus.None; op.Status = OperationStatus.None;
if (this.SchedulingPolicy is SchedulingPolicy.Interleaving) if (this.SchedulingPolicy is SchedulingPolicy.Interleaving)
{ {
@ -1244,8 +1247,7 @@ namespace Microsoft.Coyote.Runtime
this.TryEnableOperation(op); this.TryEnableOperation(op);
if (previousStatus == op.Status) if (previousStatus == op.Status)
{ {
this.LogWriter.LogDebug("[coyote::debug] Operation '{0}' of group '{1}' has status '{2}'.", this.LogWriter.LogDebug("[coyote::debug] Operation {0} has status '{1}'.", op.DebugInfo, op.Status);
op.Name, op.Group, op.Status);
if (op.IsPaused && op.IsDependencyUncontrolled) if (op.IsPaused && op.IsDependencyUncontrolled)
{ {
if (op.IsRoot) if (op.IsRoot)
@ -1260,8 +1262,8 @@ namespace Microsoft.Coyote.Runtime
} }
else else
{ {
this.LogWriter.LogDebug("[coyote::debug] Operation '{0}' of group '{1}' changed status from '{2}' to '{3}'.", this.LogWriter.LogDebug("[coyote::debug] Operation {0} changed status from '{1}' to '{2}'.",
op.Name, op.Group, previousStatus, op.Status); op.DebugInfo, previousStatus, op.Status);
statusChanges++; statusChanges++;
} }
} }
@ -1400,6 +1402,9 @@ namespace Microsoft.Coyote.Runtime
/// Returns the currently executing <see cref="ControlledOperation"/>, /// Returns the currently executing <see cref="ControlledOperation"/>,
/// or null if no such operation is executing. /// or null if no such operation is executing.
/// </summary> /// </summary>
/// <remarks>
/// Invoking this method checks if the current thread is uncontrolled or not.
/// </remarks>
internal ControlledOperation GetExecutingOperation() internal ControlledOperation GetExecutingOperation()
{ {
using (SynchronizedSection.Enter(this.RuntimeLock)) using (SynchronizedSection.Enter(this.RuntimeLock))
@ -1418,6 +1423,9 @@ namespace Microsoft.Coyote.Runtime
/// Returns the currently executing <see cref="ControlledOperation"/> of the /// Returns the currently executing <see cref="ControlledOperation"/> of the
/// specified type, or null if no such operation is executing. /// specified type, or null if no such operation is executing.
/// </summary> /// </summary>
/// <remarks>
/// Invoking this method checks if the current thread is uncontrolled or not.
/// </remarks>
internal TControlledOperation GetExecutingOperation<TControlledOperation>() internal TControlledOperation GetExecutingOperation<TControlledOperation>()
where TControlledOperation : ControlledOperation where TControlledOperation : ControlledOperation
{ {
@ -1433,6 +1441,18 @@ namespace Microsoft.Coyote.Runtime
} }
} }
/// <summary>
/// Returns the currently executing <see cref="ControlledOperation"/>,
/// or null if no such operation is executing.
/// </summary>
internal ControlledOperation GetExecutingOperationUnsafe()
{
using (SynchronizedSection.Enter(this.RuntimeLock))
{
return ExecutingOperation;
}
}
/// <summary> /// <summary>
/// Tries to return the currently executing <see cref="ControlledOperation"/>, /// Tries to return the currently executing <see cref="ControlledOperation"/>,
/// or false if no such operation is executing. /// or false if no such operation is executing.
@ -1840,7 +1860,7 @@ namespace Microsoft.Coyote.Runtime
if (pausedOperations.Count > 0) if (pausedOperations.Count > 0)
{ {
for (int idx = 0; idx < pausedOperations.Count; idx++) for (int idx = 0; idx < pausedOperations.Count; ++idx)
{ {
msg.Append(string.Format(CultureInfo.InvariantCulture, " {0}", pausedOperations[idx].Name)); msg.Append(string.Format(CultureInfo.InvariantCulture, " {0}", pausedOperations[idx].Name));
if (idx == pausedOperations.Count - 2) if (idx == pausedOperations.Count - 2)
@ -1859,7 +1879,7 @@ namespace Microsoft.Coyote.Runtime
if (pausedOnResources.Count > 0) if (pausedOnResources.Count > 0)
{ {
for (int idx = 0; idx < pausedOnResources.Count; idx++) for (int idx = 0; idx < pausedOnResources.Count; ++idx)
{ {
msg.Append(string.Format(CultureInfo.InvariantCulture, " {0}", pausedOnResources[idx].Name)); msg.Append(string.Format(CultureInfo.InvariantCulture, " {0}", pausedOnResources[idx].Name));
if (idx == pausedOnResources.Count - 2) if (idx == pausedOnResources.Count - 2)
@ -1879,7 +1899,7 @@ namespace Microsoft.Coyote.Runtime
if (pausedOnReceiveOperations.Count > 0) if (pausedOnReceiveOperations.Count > 0)
{ {
for (int idx = 0; idx < pausedOnReceiveOperations.Count; idx++) for (int idx = 0; idx < pausedOnReceiveOperations.Count; ++idx)
{ {
msg.Append(string.Format(CultureInfo.InvariantCulture, " {0}", pausedOnReceiveOperations[idx].Name)); msg.Append(string.Format(CultureInfo.InvariantCulture, " {0}", pausedOnReceiveOperations[idx].Name));
if (idx == pausedOnReceiveOperations.Count - 2) if (idx == pausedOnReceiveOperations.Count - 2)
@ -2364,7 +2384,7 @@ namespace Microsoft.Coyote.Runtime
#else #else
string[] lines = exception.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None); string[] lines = exception.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None);
#endif #endif
for (int i = 0; i < lines.Length; i++) for (int i = 0; i < lines.Length; ++i)
{ {
if (lines[i].StartsWith(" at Microsoft.Coyote.Rewriting", StringComparison.Ordinal)) if (lines[i].StartsWith(" at Microsoft.Coyote.Rewriting", StringComparison.Ordinal))
{ {
@ -2538,6 +2558,9 @@ namespace Microsoft.Coyote.Runtime
this.Id, this.Scheduler.GetStrategyName()); this.Id, this.Scheduler.GetStrategyName());
} }
// Register the explored execution path for coverage.
this.CoverageInfo.DeclareExploredExecutionPath(this.Scheduler.Trace.ToString());
this.ExecutionStatus = status; this.ExecutionStatus = status;
this.CancellationSource.Cancel(); this.CancellationSource.Cancel();

Просмотреть файл

@ -4,6 +4,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace Microsoft.Coyote.Runtime namespace Microsoft.Coyote.Runtime
{ {
@ -49,29 +50,47 @@ namespace Microsoft.Coyote.Runtime
internal static ExecutionTrace Create() => new ExecutionTrace(); internal static ExecutionTrace Create() => new ExecutionTrace();
/// <summary> /// <summary>
/// Adds a scheduling choice. /// Adds a scheduling decision.
/// </summary> /// </summary>
internal void AddSchedulingChoice(ulong scheduledOperationId, SchedulingPointType sp) internal void AddSchedulingDecision(ControlledOperation current, SchedulingPointType sp, ControlledOperation next) =>
this.AddSchedulingDecision(current.Id, current.SequenceId, sp, next.Id, next.SequenceId);
/// <summary>
/// Adds a scheduling decision.
/// </summary>
internal void AddSchedulingDecision(ulong current, ulong currentSeqId, SchedulingPointType sp, ulong next, ulong nextSeqId)
{ {
var scheduleStep = Step.CreateSchedulingChoice(this.Length, scheduledOperationId, sp); var scheduleStep = new SchedulingStep(this.Length, current, currentSeqId, sp, next, nextSeqId);
this.Push(scheduleStep); this.Push(scheduleStep);
} }
/// <summary> /// <summary>
/// Adds a nondeterministic boolean choice. /// Adds a nondeterministic boolean decision.
/// </summary> /// </summary>
internal void AddNondeterministicBooleanChoice(bool choice, SchedulingPointType sp) internal void AddNondeterministicBooleanDecision(ControlledOperation current, bool value) =>
this.AddNondeterministicBooleanDecision(current.Id, current.SequenceId, value);
/// <summary>
/// Adds a nondeterministic boolean decision.
/// </summary>
internal void AddNondeterministicBooleanDecision(ulong current, ulong currentSeqId, bool value)
{ {
var scheduleStep = Step.CreateNondeterministicBooleanChoice(this.Length, choice, sp); var scheduleStep = new BooleanChoiceStep(this.Length, current, currentSeqId, value);
this.Push(scheduleStep); this.Push(scheduleStep);
} }
/// <summary> /// <summary>
/// Adds a nondeterministic integer choice. /// Adds a nondeterministic integer decision.
/// </summary> /// </summary>
internal void AddNondeterministicIntegerChoice(int choice, SchedulingPointType sp) internal void AddNondeterministicIntegerDecision(ControlledOperation current, int value) =>
this.AddNondeterministicIntegerDecision(current.Id, current.SequenceId, value);
/// <summary>
/// Adds a nondeterministic integer decision.
/// </summary>
internal void AddNondeterministicIntegerDecision(ulong current, ulong currentSeqId, int value)
{ {
var scheduleStep = Step.CreateNondeterministicIntegerChoice(this.Length, choice, sp); var scheduleStep = new IntegerChoiceStep(this.Length, current, currentSeqId, value);
this.Push(scheduleStep); this.Push(scheduleStep);
} }
@ -143,17 +162,18 @@ namespace Microsoft.Coyote.Runtime
{ {
foreach (var step in trace.Steps) foreach (var step in trace.Steps)
{ {
if (step.Kind is DecisionKind.SchedulingChoice) if (step is SchedulingStep schedulingStep)
{ {
this.AddSchedulingChoice(step.ScheduledOperationId, step.SchedulingPoint); this.AddSchedulingDecision(schedulingStep.Current, schedulingStep.CurrentSequenceId, schedulingStep.SchedulingPoint,
schedulingStep.Value, schedulingStep.SequenceId);
} }
else if (step.Kind is DecisionKind.NondeterministicChoice && step.BooleanChoice.HasValue) else if (step is BooleanChoiceStep boolChoiceStep)
{ {
this.AddNondeterministicBooleanChoice(step.BooleanChoice.Value, step.SchedulingPoint); this.AddNondeterministicBooleanDecision(boolChoiceStep.Current, boolChoiceStep.CurrentSequenceId, boolChoiceStep.Value);
} }
else if (step.Kind is DecisionKind.NondeterministicChoice && step.IntegerChoice.HasValue) else if (step is IntegerChoiceStep intChoiceStep)
{ {
this.AddNondeterministicIntegerChoice(step.IntegerChoice.Value, step.SchedulingPoint); this.AddNondeterministicIntegerDecision(intChoiceStep.Current, intChoiceStep.CurrentSequenceId, intChoiceStep.Value);
} }
} }
@ -185,17 +205,18 @@ namespace Microsoft.Coyote.Runtime
while (appendIndex < trace.Length) while (appendIndex < trace.Length)
{ {
Step step = trace[appendIndex]; Step step = trace[appendIndex];
if (step.Kind is DecisionKind.SchedulingChoice) if (step is SchedulingStep schedulingStep)
{ {
this.AddSchedulingChoice(step.ScheduledOperationId, step.SchedulingPoint); this.AddSchedulingDecision(schedulingStep.Current, schedulingStep.CurrentSequenceId, schedulingStep.SchedulingPoint,
schedulingStep.Value, schedulingStep.SequenceId);
} }
else if (step.Kind is DecisionKind.NondeterministicChoice && step.BooleanChoice.HasValue) else if (step is BooleanChoiceStep boolChoiceStep)
{ {
this.AddNondeterministicBooleanChoice(step.BooleanChoice.Value, step.SchedulingPoint); this.AddNondeterministicBooleanDecision(boolChoiceStep.Current, boolChoiceStep.CurrentSequenceId, boolChoiceStep.Value);
} }
else if (step.Kind is DecisionKind.NondeterministicChoice && step.IntegerChoice.HasValue) else if (step is IntegerChoiceStep intChoiceStep)
{ {
this.AddNondeterministicIntegerChoice(step.IntegerChoice.Value, step.SchedulingPoint); this.AddNondeterministicIntegerDecision(intChoiceStep.Current, intChoiceStep.CurrentSequenceId, intChoiceStep.Value);
} }
appendIndex++; appendIndex++;
@ -210,18 +231,28 @@ namespace Microsoft.Coyote.Runtime
internal void Clear() => this.Steps.Clear(); internal void Clear() => this.Steps.Clear();
/// <summary> /// <summary>
/// The kind of decision taken during an execution step. /// Returns a string that represents the execution trace with all operations
/// identified by their creation sequence ids.
/// </summary> /// </summary>
internal enum DecisionKind public override string ToString()
{ {
SchedulingChoice = 0, var sb = new StringBuilder();
NondeterministicChoice for (int idx = 0; idx < this.Length; ++idx)
{
sb.Append(this.Steps[idx].ToSequenceString());
if (idx < this.Length - 1)
{
sb.Append(";");
}
}
return sb.ToString();
} }
/// <summary> /// <summary>
/// Contains metadata related to a single execution step. /// Contains metadata related to a single execution step.
/// </summary> /// </summary>
internal sealed class Step : IEquatable<Step>, IComparable<Step> internal abstract class Step : IEquatable<Step>, IComparable<Step>
{ {
/// <summary> /// <summary>
/// The unique index of this execution step. /// The unique index of this execution step.
@ -229,32 +260,14 @@ namespace Microsoft.Coyote.Runtime
internal int Index; internal int Index;
/// <summary> /// <summary>
/// The kind of controlled decision taken in this execution step. /// The id of the currently executing operation.
/// </summary> /// </summary>
internal DecisionKind Kind { get; private set; } internal ulong Current;
/// <summary> /// <summary>
/// The type of scheduling point encountered in this execution step. /// The creation sequence id of the currently executing operation.
/// </summary> /// </summary>
internal SchedulingPointType SchedulingPoint { get; private set; } internal ulong CurrentSequenceId;
/// <summary>
/// The id of the scheduled operation. Only relevant if this is
/// a regular execution step.
/// </summary>
internal ulong ScheduledOperationId;
/// <summary>
/// The non-deterministic boolean choice value. Only relevant if
/// this is a choice execution step.
/// </summary>
internal bool? BooleanChoice;
/// <summary>
/// The non-deterministic integer choice value. Only relevant if
/// this is a choice execution step.
/// </summary>
internal int? IntegerChoice;
/// <summary> /// <summary>
/// The previous execution step. /// The previous execution step.
@ -267,74 +280,27 @@ namespace Microsoft.Coyote.Runtime
internal Step Next; internal Step Next;
/// <summary> /// <summary>
/// Creates an execution step. /// Initializes a new instance of the <see cref="Step"/> class.
/// </summary> /// </summary>
internal static Step CreateSchedulingChoice(int index, ulong scheduledOperationId, SchedulingPointType sp) protected Step(int index, ulong current, ulong currentSeqId)
{ {
var scheduleStep = new Step(); this.Index = index;
scheduleStep.Index = index; this.Current = current;
scheduleStep.Kind = DecisionKind.SchedulingChoice; this.CurrentSequenceId = currentSeqId;
scheduleStep.SchedulingPoint = sp; this.Previous = null;
scheduleStep.ScheduledOperationId = scheduledOperationId; this.Next = null;
scheduleStep.BooleanChoice = null;
scheduleStep.IntegerChoice = null;
scheduleStep.Previous = null;
scheduleStep.Next = null;
return scheduleStep;
} }
/// <summary> /// <inheritdoc/>
/// Creates a nondeterministic boolean choice execution step.
/// </summary>
internal static Step CreateNondeterministicBooleanChoice(int index, bool choice, SchedulingPointType sp)
{
var scheduleStep = new Step();
scheduleStep.Index = index;
scheduleStep.Kind = DecisionKind.NondeterministicChoice;
scheduleStep.SchedulingPoint = sp;
scheduleStep.BooleanChoice = choice;
scheduleStep.IntegerChoice = null;
scheduleStep.Previous = null;
scheduleStep.Next = null;
return scheduleStep;
}
/// <summary>
/// Creates a nondeterministic integer choice execution step.
/// </summary>
internal static Step CreateNondeterministicIntegerChoice(int index, int choice, SchedulingPointType sp)
{
var scheduleStep = new Step();
scheduleStep.Index = index;
scheduleStep.Kind = DecisionKind.NondeterministicChoice;
scheduleStep.SchedulingPoint = sp;
scheduleStep.BooleanChoice = null;
scheduleStep.IntegerChoice = choice;
scheduleStep.Previous = null;
scheduleStep.Next = null;
return scheduleStep;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
public override int GetHashCode() => this.Index.GetHashCode(); public override int GetHashCode() => this.Index.GetHashCode();
/// <summary> /// <summary>
/// Indicates whether the specified <see cref="Step"/> is equal /// Indicates whether the specified <see cref="Step"/> is equal
/// to the current <see cref="Step"/>. /// to the current <see cref="Step"/>.
/// </summary> /// </summary>
internal bool Equals(Step other) => other != null ? internal abstract bool Equals(Step other);
this.Index == other.Index && this.Kind == other.Kind &&
this.SchedulingPoint == other.SchedulingPoint &&
this.ScheduledOperationId == other.ScheduledOperationId &&
this.BooleanChoice == other.BooleanChoice &&
this.IntegerChoice == other.IntegerChoice :
false;
/// <summary> /// <inheritdoc/>
/// Determines whether the specified object is equal to the current object.
/// </summary>
public override bool Equals(object obj) => this.Equals(obj as Step); public override bool Equals(object obj) => this.Equals(obj as Step);
/// <summary> /// <summary>
@ -348,6 +314,131 @@ namespace Microsoft.Coyote.Runtime
/// <see cref="Step"/> for ordering or sorting purposes. /// <see cref="Step"/> for ordering or sorting purposes.
/// </summary> /// </summary>
int IComparable<Step>.CompareTo(Step other) => this.Index - other.Index; int IComparable<Step>.CompareTo(Step other) => this.Index - other.Index;
/// <summary>
/// Returns a string that represents the execution step with all operations
/// identified by their creation sequence ids.
/// </summary>
public abstract string ToSequenceString();
}
/// <summary>
/// Contains metadata related to a single scheduling step.
/// </summary>
internal sealed class SchedulingStep : Step
{
/// <summary>
/// The type of scheduling point encountered in this execution step.
/// </summary>
internal SchedulingPointType SchedulingPoint { get; private set; }
/// <summary>
/// The id of the chosen operation.
/// </summary>
internal ulong Value;
/// <summary>
/// The creation sequence id of the chosen operation.
/// </summary>
internal ulong SequenceId;
/// <summary>
/// Initializes a new instance of the <see cref="SchedulingStep"/> class.
/// </summary>
internal SchedulingStep(int index, ulong current, ulong currentSeqId, SchedulingPointType sp, ulong next, ulong seqId)
: base(index, current, currentSeqId)
{
this.SchedulingPoint = sp;
this.Value = next;
this.SequenceId = seqId;
}
/// <inheritdoc/>
internal override bool Equals(Step other) => other is SchedulingStep step ?
this.Index == step.Index &&
this.Current == step.Current &&
this.SchedulingPoint == step.SchedulingPoint &&
this.Value == step.Value :
false;
/// <summary>
/// Returns a string that represents the execution step.
/// </summary>
public override string ToString() =>
$"op({this.Current}:{this.CurrentSequenceId}),sp({this.SchedulingPoint}),next({this.Value}:{this.SequenceId})";
/// <inheritdoc/>
public override string ToSequenceString() => $"op({this.CurrentSequenceId}),sp({this.SchedulingPoint}),next({this.SequenceId})";
}
/// <summary>
/// Contains metadata related to a single boolean choice step.
/// </summary>
internal sealed class BooleanChoiceStep : Step
{
/// <summary>
/// The chosen boolean value.
/// </summary>
internal bool Value;
/// <summary>
/// Initializes a new instance of the <see cref="BooleanChoiceStep"/> class.
/// </summary>
internal BooleanChoiceStep(int index, ulong current, ulong currentSeqId, bool value)
: base(index, current, currentSeqId)
{
this.Value = value;
}
/// <inheritdoc/>
internal override bool Equals(Step other) => other is BooleanChoiceStep step ?
this.Index == step.Index &&
this.Current == step.Current &&
this.Value == step.Value :
false;
/// <summary>
/// Returns a string that represents the execution step.
/// </summary>
public override string ToString() => $"op({this.Current}:{this.CurrentSequenceId}),bool({this.Value})";
/// <inheritdoc/>
public override string ToSequenceString() => $"op({this.CurrentSequenceId}),bool({this.Value})";
}
/// <summary>
/// Contains metadata related to a single integer choice step.
/// </summary>
internal sealed class IntegerChoiceStep : Step
{
/// <summary>
/// The chosen integer value.
/// </summary>
internal int Value;
/// <summary>
/// Initializes a new instance of the <see cref="IntegerChoiceStep"/> class.
/// </summary>
internal IntegerChoiceStep(int index, ulong current, ulong currentSeqId, int value)
: base(index, current, currentSeqId)
{
this.Value = value;
}
/// <inheritdoc/>
internal override bool Equals(Step other) => other is IntegerChoiceStep step ?
this.Index == step.Index &&
this.Current == step.Current &&
this.Value == step.Value :
false;
/// <summary>
/// Returns a string that represents the execution step.
/// </summary>
public override string ToString() => $"op({this.Current}:{this.CurrentSequenceId}),int({this.Value})";
/// <inheritdoc/>
public override string ToSequenceString() => $"op({this.CurrentSequenceId}),int({this.Value})";
} }
} }
} }

Просмотреть файл

@ -22,6 +22,11 @@ namespace Microsoft.Coyote.Runtime
/// </summary> /// </summary>
internal ulong Id { get; } internal ulong Id { get; }
/// <summary>
/// The creation sequence id of this operation.
/// </summary>
internal ulong SequenceId { get; }
/// <summary> /// <summary>
/// The name of this operation. /// The name of this operation.
/// </summary> /// </summary>
@ -39,6 +44,11 @@ namespace Microsoft.Coyote.Runtime
/// </summary> /// </summary>
internal readonly OperationGroup Group; internal readonly OperationGroup Group;
/// <summary>
/// The creation sequence of this operation.
/// </summary>
private readonly List<ulong> Sequence;
/// <summary> /// <summary>
/// Queue of continuations that this operation must execute before it completes. /// Queue of continuations that this operation must execute before it completes.
/// </summary> /// </summary>
@ -77,6 +87,11 @@ namespace Microsoft.Coyote.Runtime
/// </summary> /// </summary>
internal IEqualityComparer<string> LastAccessedSharedStateComparer; internal IEqualityComparer<string> LastAccessedSharedStateComparer;
/// <summary>
/// The count of operations created by this operation.
/// </summary>
internal ulong OperationCreationCount;
/// <summary> /// <summary>
/// True if the source of this operation is uncontrolled, else false. /// True if the source of this operation is uncontrolled, else false.
/// </summary> /// </summary>
@ -87,6 +102,11 @@ namespace Microsoft.Coyote.Runtime
/// </summary> /// </summary>
internal bool IsDependencyUncontrolled; internal bool IsDependencyUncontrolled;
/// <summary>
/// The debug information of this operation.
/// </summary>
internal string DebugInfo { get; }
/// <summary> /// <summary>
/// True if this is the root operation, else false. /// True if this is the root operation, else false.
/// </summary> /// </summary>
@ -117,9 +137,27 @@ namespace Microsoft.Coyote.Runtime
this.LastHashedProgramState = 0; this.LastHashedProgramState = 0;
this.LastAccessedSharedState = string.Empty; this.LastAccessedSharedState = string.Empty;
this.LastAccessedSharedStateComparer = null; this.LastAccessedSharedStateComparer = null;
this.OperationCreationCount = 0;
this.IsSourceUncontrolled = false; this.IsSourceUncontrolled = false;
this.IsDependencyUncontrolled = false; this.IsDependencyUncontrolled = false;
// Only compute the sequence if the runtime scheduler is controlled.
if (this.Runtime.SchedulingPolicy is SchedulingPolicy.None)
{
this.SequenceId = 0;
}
else
{
// If no parent operation is found, and this is not the root operation, then assign the root operation as the
// parent operation. This is just an approximation that is applied in the case of uncontrolled threads.
ControlledOperation parent = this.Runtime.GetExecutingOperationUnsafe() ?? this.Runtime.GetOperationWithId(0);
this.Sequence = GetSequenceFromParent(operationId, parent);
this.SequenceId = this.GetSequenceHash();
}
// Set the debug information for this operation.
this.DebugInfo = $"'{this.Name}' with sequence id '{this.SequenceId}' and group id '{this.Group.Id}'";
// Register this operation with the runtime. // Register this operation with the runtime.
this.Runtime.RegisterNewOperation(this); this.Runtime.RegisterNewOperation(this);
} }
@ -193,6 +231,45 @@ namespace Microsoft.Coyote.Runtime
return this.Status is OperationStatus.Enabled; return this.Status is OperationStatus.Enabled;
} }
/// <summary>
/// Returns the creation sequence based on the specified parent operation.
/// </summary>
private static List<ulong> GetSequenceFromParent(ulong operationId, ControlledOperation parent)
{
var sequence = new List<ulong>();
if (operationId is 0)
{
// If this is the root operation, then the sequence only contains the root operation itself.
sequence.Add(0);
}
else
{
sequence.AddRange(parent.Sequence);
sequence.Add(parent.OperationCreationCount);
parent.OperationCreationCount++;
}
return sequence;
}
/// <summary>
/// Returns the hash of the creation sequence.
/// </summary>
private ulong GetSequenceHash()
{
// Iterate the creation sequence and create a low collision rate hash.
ulong hash = (ulong)this.Sequence.Count;
foreach (ulong element in this.Sequence)
{
ulong seq = ((element >> 16) ^ element) * 0x45d9f3b;
seq = ((seq >> 16) ^ seq) * 0x45d9f3b;
seq = (seq >> 16) ^ seq;
hash ^= seq + 0x9e3779b9 + (hash << 6) + (hash >> 2);
}
return hash;
}
/// <summary> /// <summary>
/// Returns the hashed state of this operation for the specified policy. /// Returns the hashed state of this operation for the specified policy.
/// </summary> /// </summary>

Просмотреть файл

@ -250,7 +250,7 @@ namespace Microsoft.Coyote.Runtime
if (this.Strategy is InterleavingStrategy strategy && if (this.Strategy is InterleavingStrategy strategy &&
strategy.GetNextOperation(enabledOps, current, isYielding, out next)) strategy.GetNextOperation(enabledOps, current, isYielding, out next))
{ {
this.Trace.AddSchedulingChoice(next.Id, current.LastSchedulingPoint); this.Trace.AddSchedulingDecision(current, current.LastSchedulingPoint, next);
return true; return true;
} }
} }
@ -270,7 +270,7 @@ namespace Microsoft.Coyote.Runtime
if (this.Strategy is InterleavingStrategy strategy && if (this.Strategy is InterleavingStrategy strategy &&
strategy.GetNextBoolean(current, out next)) strategy.GetNextBoolean(current, out next))
{ {
this.Trace.AddNondeterministicBooleanChoice(next, current.LastSchedulingPoint); this.Trace.AddNondeterministicBooleanDecision(current, next);
return true; return true;
} }
@ -290,7 +290,7 @@ namespace Microsoft.Coyote.Runtime
if (this.Strategy is InterleavingStrategy strategy && if (this.Strategy is InterleavingStrategy strategy &&
strategy.GetNextInteger(current, maxValue, out next)) strategy.GetNextInteger(current, maxValue, out next))
{ {
this.Trace.AddNondeterministicIntegerChoice(next, current.LastSchedulingPoint); this.Trace.AddNondeterministicIntegerDecision(current, next);
return true; return true;
} }

Просмотреть файл

@ -235,7 +235,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
else else
{ {
ncs = new List<NondetIntegerChoice>(); ncs = new List<NondetIntegerChoice>();
for (int value = 0; value < maxValue; value++) for (int value = 0; value < maxValue; ++value)
{ {
ncs.Add(new NondetIntegerChoice(value)); ncs.Add(new NondetIntegerChoice(value));
} }
@ -278,7 +278,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.AppendLine("*******************"); sb.AppendLine("*******************");
sb.AppendLine($"Schedule stack size: {this.ScheduleStack.Count}"); sb.AppendLine($"Schedule stack size: {this.ScheduleStack.Count}");
for (int idx = 0; idx < this.ScheduleStack.Count; idx++) for (int idx = 0; idx < this.ScheduleStack.Count; ++idx)
{ {
sb.AppendLine($"Index: {idx}"); sb.AppendLine($"Index: {idx}");
foreach (var sc in this.ScheduleStack[idx]) foreach (var sc in this.ScheduleStack[idx])
@ -291,7 +291,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
sb.AppendLine("*******************"); sb.AppendLine("*******************");
sb.AppendLine($"Random bool stack size: {this.BoolNondetStack.Count}"); sb.AppendLine($"Random bool stack size: {this.BoolNondetStack.Count}");
for (int idx = 0; idx < this.BoolNondetStack.Count; idx++) for (int idx = 0; idx < this.BoolNondetStack.Count; ++idx)
{ {
sb.AppendLine($"Index: {idx}"); sb.AppendLine($"Index: {idx}");
foreach (var nc in this.BoolNondetStack[idx]) foreach (var nc in this.BoolNondetStack[idx])
@ -304,7 +304,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
sb.AppendLine("*******************"); sb.AppendLine("*******************");
sb.AppendLine($"Random int stack size: {this.IntNondetStack.Count}"); sb.AppendLine($"Random int stack size: {this.IntNondetStack.Count}");
for (int idx = 0; idx < this.IntNondetStack.Count; idx++) for (int idx = 0; idx < this.IntNondetStack.Count; ++idx)
{ {
sb.AppendLine($"Index: {idx}"); sb.AppendLine($"Index: {idx}");
foreach (var nc in this.IntNondetStack[idx]) foreach (var nc in this.IntNondetStack[idx])

Просмотреть файл

@ -68,7 +68,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
if (this.MaxDelaysPerIteration > 0) if (this.MaxDelaysPerIteration > 0)
{ {
var delays = this.RandomValueGenerator.Next(this.MaxDelaysPerIteration) + 1; var delays = this.RandomValueGenerator.Next(this.MaxDelaysPerIteration) + 1;
for (int i = 0; i < delays; i++) for (int i = 0; i < delays; ++i)
{ {
this.DelayPoints.Add(this.RandomValueGenerator.Next(this.MaxDelayPoints + 1)); this.DelayPoints.Add(this.RandomValueGenerator.Next(this.MaxDelayPoints + 1));
} }
@ -192,7 +192,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("[coyote::strategy] Updated operation group round-robin list: "); sb.AppendLine("[coyote::strategy] Updated operation group round-robin list: ");
for (int idx = 0; idx < this.OperationGroups.Count; idx++) for (int idx = 0; idx < this.OperationGroups.Count; ++idx)
{ {
var group = this.OperationGroups[idx]; var group = this.OperationGroups[idx];
if (group.Any(m => m.Status is OperationStatus.Enabled)) if (group.Any(m => m.Status is OperationStatus.Enabled))

Просмотреть файл

@ -51,23 +51,26 @@ namespace Microsoft.Coyote.Testing.Interleaving
if (this.StepCount < this.TracePrefix.Length) if (this.StepCount < this.TracePrefix.Length)
{ {
ExecutionTrace.Step nextStep = this.TracePrefix[this.StepCount]; ExecutionTrace.Step nextStep = this.TracePrefix[this.StepCount];
if (nextStep.Kind != ExecutionTrace.DecisionKind.SchedulingChoice) if (nextStep is ExecutionTrace.SchedulingStep step)
{
next = ops.FirstOrDefault(op => op.Id == step.Value);
if (next is null)
{
this.ErrorText = this.FormatReplayError(nextStep.Index, $"cannot detect id '{step.Value}'");
throw new InvalidOperationException(this.ErrorText);
}
else if (step.SchedulingPoint != current.LastSchedulingPoint)
{
this.ErrorText = this.FormatReplayError(nextStep.Index,
$"expected scheduling point '{step.SchedulingPoint}' instead of '{current.LastSchedulingPoint}'");
throw new InvalidOperationException(this.ErrorText);
}
}
else
{ {
this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a scheduling choice"); this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a scheduling choice");
throw new InvalidOperationException(this.ErrorText); throw new InvalidOperationException(this.ErrorText);
} }
next = ops.FirstOrDefault(op => op.Id == nextStep.ScheduledOperationId);
if (next is null)
{
this.ErrorText = this.FormatReplayError(nextStep.Index, $"cannot detect id '{nextStep.ScheduledOperationId}'");
throw new InvalidOperationException(this.ErrorText);
}
else if (nextStep.SchedulingPoint != current.LastSchedulingPoint)
{
this.ErrorText = this.FormatSchedulingPointReplayError(nextStep.Index, nextStep.SchedulingPoint, current.LastSchedulingPoint);
throw new InvalidOperationException(this.ErrorText);
}
} }
else else
{ {
@ -110,24 +113,15 @@ namespace Microsoft.Coyote.Testing.Interleaving
if (this.StepCount < this.TracePrefix.Length) if (this.StepCount < this.TracePrefix.Length)
{ {
ExecutionTrace.Step nextStep = this.TracePrefix[this.StepCount]; ExecutionTrace.Step nextStep = this.TracePrefix[this.StepCount];
if (nextStep.Kind != ExecutionTrace.DecisionKind.NondeterministicChoice) if (nextStep is ExecutionTrace.BooleanChoiceStep step)
{
next = step.Value;
}
else
{ {
this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a nondeterministic choice"); this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a nondeterministic choice");
throw new InvalidOperationException(this.ErrorText); throw new InvalidOperationException(this.ErrorText);
} }
if (nextStep.BooleanChoice is null)
{
this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a nondeterministic boolean choice");
throw new InvalidOperationException(this.ErrorText);
}
else if (nextStep.SchedulingPoint != current.LastSchedulingPoint)
{
this.ErrorText = this.FormatSchedulingPointReplayError(nextStep.Index, nextStep.SchedulingPoint, current.LastSchedulingPoint);
throw new InvalidOperationException(this.ErrorText);
}
next = nextStep.BooleanChoice.Value;
} }
else else
{ {
@ -168,24 +162,15 @@ namespace Microsoft.Coyote.Testing.Interleaving
if (this.StepCount < this.TracePrefix.Length) if (this.StepCount < this.TracePrefix.Length)
{ {
ExecutionTrace.Step nextStep = this.TracePrefix[this.StepCount]; ExecutionTrace.Step nextStep = this.TracePrefix[this.StepCount];
if (nextStep.Kind != ExecutionTrace.DecisionKind.NondeterministicChoice) if (nextStep is ExecutionTrace.IntegerChoiceStep step)
{
next = step.Value;
}
else
{ {
this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a nondeterministic choice"); this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a nondeterministic choice");
throw new InvalidOperationException(this.ErrorText); throw new InvalidOperationException(this.ErrorText);
} }
if (nextStep.IntegerChoice is null)
{
this.ErrorText = this.FormatReplayError(nextStep.Index, "next step is not a nondeterministic integer choice");
throw new InvalidOperationException(this.ErrorText);
}
else if (nextStep.SchedulingPoint != current.LastSchedulingPoint)
{
this.ErrorText = this.FormatSchedulingPointReplayError(nextStep.Index, nextStep.SchedulingPoint, current.LastSchedulingPoint);
throw new InvalidOperationException(this.ErrorText);
}
next = nextStep.IntegerChoice.Value;
} }
else else
{ {
@ -220,12 +205,6 @@ namespace Microsoft.Coyote.Testing.Interleaving
/// </remarks> /// </remarks>
internal virtual void Reset() => this.StepCount = 0; internal virtual void Reset() => this.StepCount = 0;
/// <summary>
/// Formats the error message regarding an unexpected scheduling point.
/// </summary>
private string FormatSchedulingPointReplayError(int step, SchedulingPointType expected, SchedulingPointType actual) =>
this.FormatReplayError(step, $"expected scheduling point '{expected}' instead of '{actual}'");
/// <summary> /// <summary>
/// Formats the error message. /// Formats the error message.
/// </summary> /// </summary>

Просмотреть файл

@ -221,7 +221,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("[coyote::strategy] Updated operation group priority list: "); sb.AppendLine("[coyote::strategy] Updated operation group priority list: ");
for (int idx = 0; idx < this.PrioritizedOperationGroups.Count; idx++) for (int idx = 0; idx < this.PrioritizedOperationGroups.Count; ++idx)
{ {
var group = this.PrioritizedOperationGroups[idx]; var group = this.PrioritizedOperationGroups[idx];
if (group.Any(m => m.Status is OperationStatus.Enabled)) if (group.Any(m => m.Status is OperationStatus.Enabled))

Просмотреть файл

@ -58,7 +58,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
/// </summary> /// </summary>
private bool ShouldCurrentOperationChange() private bool ShouldCurrentOperationChange()
{ {
for (int idx = 0; idx < this.Bound; idx++) for (int idx = 0; idx < this.Bound; ++idx)
{ {
if (this.RandomValueGenerator.Next(2) is 1) if (this.RandomValueGenerator.Next(2) is 1)
{ {

Просмотреть файл

@ -190,7 +190,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
private int GetNextIntegerChoiceByPolicy(int state, int maxValue) private int GetNextIntegerChoiceByPolicy(int state, int maxValue)
{ {
var qValues = new List<double>(maxValue); var qValues = new List<double>(maxValue);
for (ulong i = 0; i < (ulong)maxValue; i++) for (ulong i = 0; i < (ulong)maxValue; ++i)
{ {
qValues.Add(this.OperationQTable[state][this.MinIntegerChoiceOpValue - i]); qValues.Add(this.OperationQTable[state][this.MinIntegerChoiceOpValue - i]);
} }
@ -205,13 +205,13 @@ namespace Microsoft.Coyote.Testing.Interleaving
private int ChooseQValueIndexFromDistribution(List<double> qValues) private int ChooseQValueIndexFromDistribution(List<double> qValues)
{ {
double sum = 0; double sum = 0;
for (int i = 0; i < qValues.Count; i++) for (int i = 0; i < qValues.Count; ++i)
{ {
qValues[i] = Math.Exp(qValues[i]); qValues[i] = Math.Exp(qValues[i]);
sum += qValues[i]; sum += qValues[i];
} }
for (int i = 0; i < qValues.Count; i++) for (int i = 0; i < qValues.Count; ++i)
{ {
qValues[i] /= sum; qValues[i] /= sum;
} }
@ -331,7 +331,7 @@ namespace Microsoft.Coyote.Testing.Interleaving
this.OperationQTable.Add(state, qValues); this.OperationQTable.Add(state, qValues);
} }
for (ulong i = 0; i < (ulong)maxValue; i++) for (ulong i = 0; i < (ulong)maxValue; ++i)
{ {
ulong opValue = this.MinIntegerChoiceOpValue - i; ulong opValue = this.MinIntegerChoiceOpValue - i;
if (!qValues.ContainsKey(opValue)) if (!qValues.ContainsKey(opValue))

Просмотреть файл

@ -40,7 +40,7 @@ namespace Microsoft.Coyote.Rewriting
if (method.Name == name && method.Parameters.Count == parameterTypes.Length) if (method.Name == name && method.Parameters.Count == parameterTypes.Length)
{ {
bool isMatch = true; bool isMatch = true;
for (int i = 0; isMatch && i < method.Parameters.Count; i++) for (int i = 0; isMatch && i < method.Parameters.Count; ++i)
{ {
var left = parameterTypes[i]; var left = parameterTypes[i];
var right = method.Parameters[i].ParameterType; var right = method.Parameters[i].ParameterType;

Просмотреть файл

@ -183,7 +183,7 @@ namespace Microsoft.Coyote.Rewriting
// if it has, find the rewritten method. The signature does not include the return // if it has, find the rewritten method. The signature does not include the return
// type according to C# rules, so we do not take it into account. // type according to C# rules, so we do not take it into account.
List<TypeReference> paramTypes = new List<TypeReference>(); List<TypeReference> paramTypes = new List<TypeReference>();
for (int i = 0; i < method.Parameters.Count; i++) for (int i = 0; i < method.Parameters.Count; ++i)
{ {
var p = method.Parameters[i]; var p = method.Parameters[i];
paramTypes.Add(this.RewriteType(p.ParameterType, Options.None)); paramTypes.Add(this.RewriteType(p.ParameterType, Options.None));
@ -282,7 +282,7 @@ namespace Microsoft.Coyote.Rewriting
Collection<TypeReference> genericArguments, ref bool isRewritten) Collection<TypeReference> genericArguments, ref bool isRewritten)
{ {
var genericMethod = new GenericInstanceMethod(method); var genericMethod = new GenericInstanceMethod(method);
for (int i = 0; i < genericArguments.Count; i++) for (int i = 0; i < genericArguments.Count; ++i)
{ {
GenericParameter parameter = new GenericParameter(genericParameters[i].Name, genericMethod); GenericParameter parameter = new GenericParameter(genericParameters[i].Name, genericMethod);
method.GenericParameters.Add(parameter); method.GenericParameters.Add(parameter);
@ -301,7 +301,7 @@ namespace Microsoft.Coyote.Rewriting
private MethodReference RewriteParameters(MethodReference method, Collection<ParameterDefinition> parameters, private MethodReference RewriteParameters(MethodReference method, Collection<ParameterDefinition> parameters,
ref bool isRewritten) ref bool isRewritten)
{ {
for (int i = 0; i < parameters.Count; i++) for (int i = 0; i < parameters.Count; ++i)
{ {
// Try rewrite the parameter only if the declaring type is a non-runtime type, // Try rewrite the parameter only if the declaring type is a non-runtime type,
// else assign the generic arguments if the parameter is generic. // else assign the generic arguments if the parameter is generic.
@ -347,7 +347,7 @@ namespace Microsoft.Coyote.Rewriting
return false; return false;
} }
for (int idx = 0; idx < right.Parameters.Count; idx++) for (int idx = 0; idx < right.Parameters.Count; ++idx)
{ {
var leftParam = left.Parameters[idx]; var leftParam = left.Parameters[idx];
var rightParam = right.Parameters[idx]; var rightParam = right.Parameters[idx];
@ -407,7 +407,7 @@ namespace Microsoft.Coyote.Rewriting
} }
// Check if the parameters match. // Check if the parameters match.
for (int idx = 0; idx < originalMethod.Parameters.Count; idx++) for (int idx = 0; idx < originalMethod.Parameters.Count; ++idx)
{ {
// If we are converting to static, we have one extra parameter, so skip it. // If we are converting to static, we have one extra parameter, so skip it.
var newParameter = newMethod.Parameters[isConvertedToStatic ? idx + 1 : idx]; var newParameter = newMethod.Parameters[isConvertedToStatic ? idx + 1 : idx];

Просмотреть файл

@ -172,7 +172,7 @@ namespace Microsoft.Coyote.Rewriting
onlyImport, ref isRewritten); onlyImport, ref isRewritten);
GenericInstanceType newGenericType = newElementType as GenericInstanceType ?? GenericInstanceType newGenericType = newElementType as GenericInstanceType ??
new GenericInstanceType(newElementType); new GenericInstanceType(newElementType);
for (int idx = 0; idx < genericType.GenericArguments.Count; idx++) for (int idx = 0; idx < genericType.GenericArguments.Count; ++idx)
{ {
newGenericType.GenericArguments.Add(this.RewriteType(genericType.GenericArguments[idx], newGenericType.GenericArguments.Add(this.RewriteType(genericType.GenericArguments[idx],
options & ~Options.AllowStaticRewrittenType, false, ref isRewritten)); options & ~Options.AllowStaticRewrittenType, false, ref isRewritten));

Просмотреть файл

@ -303,8 +303,8 @@ namespace Microsoft.Coyote.Rewriting.Types.Threading
} }
runtime.LogWriter.LogDebug( runtime.LogWriter.LogDebug(
"[coyote::debug] Operation '{0}' of group '{1}' is waiting for '{2}' to get released on thread '{3}'.", "[coyote::debug] Operation {0} is waiting for '{1}' to get released on thread '{2}'.",
current.Name, current.Group, this.DebugName, SystemThread.CurrentThread.ManagedThreadId); current.DebugInfo, this.DebugName, SystemThread.CurrentThread.ManagedThreadId);
current.Status = OperationStatus.PausedOnResource; current.Status = OperationStatus.PausedOnResource;
this.PausedOperations.Enqueue(current); this.PausedOperations.Enqueue(current);
runtime.ScheduleNextOperation(current, SchedulingPointType.Pause); runtime.ScheduleNextOperation(current, SchedulingPointType.Pause);

Просмотреть файл

@ -29,16 +29,16 @@ namespace Microsoft.Coyote.SystematicTesting
public ActorCoverageInfo CoverageInfo { get; private set; } public ActorCoverageInfo CoverageInfo { get; private set; }
/// <summary> /// <summary>
/// Number of explored fair schedules. /// Number of explored fair execution paths.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int NumOfExploredFairSchedules { get; internal set; } public int NumOfExploredFairPaths { get; internal set; }
/// <summary> /// <summary>
/// Number of explored unfair schedules. /// Number of explored unfair execution paths.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int NumOfExploredUnfairSchedules { get; internal set; } public int NumOfExploredUnfairPaths { get; internal set; }
/// <summary> /// <summary>
/// Number of found bugs. /// Number of found bugs.
@ -113,37 +113,37 @@ namespace Microsoft.Coyote.SystematicTesting
public int TotalOperationGroupingDegree { get; internal set; } public int TotalOperationGroupingDegree { get; internal set; }
/// <summary> /// <summary>
/// The min explored scheduling steps in fair tests. /// The min explored execution steps in fair tests.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int MinExploredFairSteps { get; internal set; } public int MinExploredFairSteps { get; internal set; }
/// <summary> /// <summary>
/// The max explored scheduling steps in fair tests. /// The max explored execution steps in fair tests.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int MaxExploredFairSteps { get; internal set; } public int MaxExploredFairSteps { get; internal set; }
/// <summary> /// <summary>
/// The total explored scheduling steps (across all testing iterations) in fair tests. /// The total explored execution steps (across all testing iterations) in fair tests.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int TotalExploredFairSteps { get; internal set; } public int TotalExploredFairSteps { get; internal set; }
/// <summary> /// <summary>
/// The min explored scheduling steps in unfair tests. /// The min explored execution steps in unfair tests.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int MinExploredUnfairSteps { get; internal set; } public int MinExploredUnfairSteps { get; internal set; }
/// <summary> /// <summary>
/// The max explored scheduling steps in unfair tests. /// The max explored execution steps in unfair tests.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int MaxExploredUnfairSteps { get; internal set; } public int MaxExploredUnfairSteps { get; internal set; }
/// <summary> /// <summary>
/// The total explored scheduling steps (across all testing iterations) in unfair tests. /// The total explored execution steps (across all testing iterations) in unfair tests.
/// </summary> /// </summary>
[DataMember] [DataMember]
public int TotalExploredUnfairSteps { get; internal set; } public int TotalExploredUnfairSteps { get; internal set; }
@ -191,8 +191,8 @@ namespace Microsoft.Coyote.SystematicTesting
this.CoverageInfo = new ActorCoverageInfo(); this.CoverageInfo = new ActorCoverageInfo();
this.NumOfExploredFairSchedules = 0; this.NumOfExploredFairPaths = 0;
this.NumOfExploredUnfairSchedules = 0; this.NumOfExploredUnfairPaths = 0;
this.NumOfFoundBugs = 0; this.NumOfFoundBugs = 0;
this.BugReports = new HashSet<string>(); this.BugReports = new HashSet<string>();
this.UncontrolledInvocations = new HashSet<string>(); this.UncontrolledInvocations = new HashSet<string>();
@ -223,7 +223,7 @@ namespace Microsoft.Coyote.SystematicTesting
/// <inheritdoc/> /// <inheritdoc/>
void ITestReport.SetSchedulingStatistics(bool isBugFound, string bugReport, int numOperations, int concurrencyDegree, void ITestReport.SetSchedulingStatistics(bool isBugFound, string bugReport, int numOperations, int concurrencyDegree,
int groupingDegree, int scheduledSteps, bool isMaxScheduledStepsBoundReached, bool isScheduleFair) int groupingDegree, int executionSteps, bool isMaxStepsBoundReached, bool isExecutionPathFair)
{ {
if (isBugFound) if (isBugFound)
{ {
@ -255,39 +255,39 @@ namespace Microsoft.Coyote.SystematicTesting
this.MinOperationGroupingDegree = groupingDegree; this.MinOperationGroupingDegree = groupingDegree;
} }
if (isScheduleFair) if (isExecutionPathFair)
{ {
this.NumOfExploredFairSchedules++; this.NumOfExploredFairPaths++;
this.TotalExploredFairSteps += scheduledSteps; this.TotalExploredFairSteps += executionSteps;
this.MaxExploredFairSteps = Math.Max(this.MaxExploredFairSteps, scheduledSteps); this.MaxExploredFairSteps = Math.Max(this.MaxExploredFairSteps, executionSteps);
if (this.MinExploredFairSteps < 0 || if (this.MinExploredFairSteps < 0 ||
this.MinExploredFairSteps > scheduledSteps) this.MinExploredFairSteps > executionSteps)
{ {
this.MinExploredFairSteps = scheduledSteps; this.MinExploredFairSteps = executionSteps;
} }
if (isMaxScheduledStepsBoundReached) if (isMaxStepsBoundReached)
{ {
this.MaxFairStepsHitInFairTests++; this.MaxFairStepsHitInFairTests++;
} }
if (scheduledSteps >= this.Configuration.MaxUnfairSchedulingSteps) if (executionSteps >= this.Configuration.MaxUnfairSchedulingSteps)
{ {
this.MaxUnfairStepsHitInFairTests++; this.MaxUnfairStepsHitInFairTests++;
} }
} }
else else
{ {
this.NumOfExploredUnfairSchedules++; this.NumOfExploredUnfairPaths++;
this.TotalExploredUnfairSteps += scheduledSteps; this.TotalExploredUnfairSteps += executionSteps;
this.MaxExploredUnfairSteps = Math.Max(this.MaxExploredUnfairSteps, scheduledSteps); this.MaxExploredUnfairSteps = Math.Max(this.MaxExploredUnfairSteps, executionSteps);
if (this.MinExploredUnfairSteps < 0 || if (this.MinExploredUnfairSteps < 0 ||
this.MinExploredUnfairSteps > scheduledSteps) this.MinExploredUnfairSteps > executionSteps)
{ {
this.MinExploredUnfairSteps = scheduledSteps; this.MinExploredUnfairSteps = executionSteps;
} }
if (isMaxScheduledStepsBoundReached) if (isMaxStepsBoundReached)
{ {
this.MaxUnfairStepsHitInUnfairTests++; this.MaxUnfairStepsHitInUnfairTests++;
} }
@ -354,8 +354,8 @@ namespace Microsoft.Coyote.SystematicTesting
this.MinOperationGroupingDegree = testReport.MinOperationGroupingDegree; this.MinOperationGroupingDegree = testReport.MinOperationGroupingDegree;
} }
this.NumOfExploredFairSchedules += testReport.NumOfExploredFairSchedules; this.NumOfExploredFairPaths += testReport.NumOfExploredFairPaths;
this.NumOfExploredUnfairSchedules += testReport.NumOfExploredUnfairSchedules; this.NumOfExploredUnfairPaths += testReport.NumOfExploredUnfairPaths;
this.TotalExploredFairSteps += testReport.TotalExploredFairSteps; this.TotalExploredFairSteps += testReport.TotalExploredFairSteps;
this.MaxExploredFairSteps = Math.Max(this.MaxExploredFairSteps, testReport.MaxExploredFairSteps); this.MaxExploredFairSteps = Math.Max(this.MaxExploredFairSteps, testReport.MaxExploredFairSteps);
@ -420,26 +420,27 @@ namespace Microsoft.Coyote.SystematicTesting
report.AppendLine(); report.AppendLine();
report.AppendFormat("{0} Scheduling statistics:", prefix); report.AppendFormat("{0} Scheduling statistics:", prefix);
int totalExploredSchedules = this.NumOfExploredFairSchedules + int totalExploredPaths = this.NumOfExploredFairPaths +
this.NumOfExploredUnfairSchedules; this.NumOfExploredUnfairPaths;
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Explored {1} schedule{2}: {3} fair and {4} unfair.", "{0} Explored {1} execution path{2}: {3} fair, {4} unfair, {5} unique.",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
totalExploredSchedules, totalExploredPaths,
totalExploredSchedules is 1 ? string.Empty : "s", totalExploredPaths is 1 ? string.Empty : "s",
this.NumOfExploredFairSchedules, this.NumOfExploredFairPaths,
this.NumOfExploredUnfairSchedules); this.NumOfExploredUnfairPaths,
this.CoverageInfo.ExploredPaths.Count);
if (totalExploredSchedules > 0 && if (totalExploredPaths > 0 &&
this.NumOfFoundBugs > 0) this.NumOfFoundBugs > 0)
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Found {1:F2}% buggy schedules.", "{0} Found {1:F2}% buggy execution paths.",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
this.NumOfFoundBugs * 100.0 / totalExploredSchedules); this.NumOfFoundBugs * 100.0 / totalExploredPaths);
} }
int visitedStatesCount = this.CoverageInfo.VisitedStates.Count; int visitedStatesCount = this.CoverageInfo.VisitedStates.Count;
@ -447,7 +448,7 @@ namespace Microsoft.Coyote.SystematicTesting
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Visited {1} state{2}.", "{0} Visited {1} unique state{2}.",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
visitedStatesCount, visitedStatesCount,
visitedStatesCount is 1 ? string.Empty : "s"); visitedStatesCount is 1 ? string.Empty : "s");
@ -457,13 +458,14 @@ namespace Microsoft.Coyote.SystematicTesting
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Controlled {1} operation{2}: {3} (min), {4} (avg), {5} (max).", "{0} Controlled {1} operation{2}: {3} (min), {4} (avg), {5} (max), {6} (unique).",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
this.TotalControlledOperations, this.TotalControlledOperations,
this.TotalControlledOperations is 1 ? string.Empty : "s", this.TotalControlledOperations is 1 ? string.Empty : "s",
this.MinControlledOperations, this.MinControlledOperations,
this.TotalControlledOperations / totalExploredSchedules, this.TotalControlledOperations / totalExploredPaths,
this.MaxControlledOperations); this.MaxControlledOperations,
this.CoverageInfo.OperationSequenceIds.Count);
} }
if (this.TotalConcurrencyDegree > 0) if (this.TotalConcurrencyDegree > 0)
@ -473,7 +475,7 @@ namespace Microsoft.Coyote.SystematicTesting
"{0} Degree of concurrency: {1} (min), {2} (avg), {3} (max).", "{0} Degree of concurrency: {1} (min), {2} (avg), {3} (max).",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
this.MinConcurrencyDegree, this.MinConcurrencyDegree,
this.TotalConcurrencyDegree / totalExploredSchedules, this.TotalConcurrencyDegree / totalExploredPaths,
this.MaxConcurrencyDegree); this.MaxConcurrencyDegree);
} }
@ -484,18 +486,18 @@ namespace Microsoft.Coyote.SystematicTesting
"{0} Degree of operation grouping: {1} (min), {2} (avg), {3} (max).", "{0} Degree of operation grouping: {1} (min), {2} (avg), {3} (max).",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
this.MinOperationGroupingDegree, this.MinOperationGroupingDegree,
this.TotalOperationGroupingDegree / totalExploredSchedules, this.TotalOperationGroupingDegree / totalExploredPaths,
this.MaxOperationGroupingDegree); this.MaxOperationGroupingDegree);
} }
if (this.NumOfExploredFairSchedules > 0) if (this.NumOfExploredFairPaths > 0)
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Number of scheduling decisions in fair terminating schedules: {1} (min), {2} (avg), {3} (max).", "{0} Number of scheduling decisions in fair terminating execution paths: {1} (min), {2} (avg), {3} (max).",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
this.MinExploredFairSteps < 0 ? 0 : this.MinExploredFairSteps, this.MinExploredFairSteps < 0 ? 0 : this.MinExploredFairSteps,
this.TotalExploredFairSteps / this.NumOfExploredFairSchedules, this.TotalExploredFairSteps / this.NumOfExploredFairPaths,
this.MaxExploredFairSteps < 0 ? 0 : this.MaxExploredFairSteps); this.MaxExploredFairSteps < 0 ? 0 : this.MaxExploredFairSteps);
if (configuration.MaxUnfairSchedulingSteps > 0 && if (configuration.MaxUnfairSchedulingSteps > 0 &&
@ -503,10 +505,10 @@ namespace Microsoft.Coyote.SystematicTesting
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Exceeded the max-steps bound of '{1}' in {2:F2}% of the fair schedules.", "{0} Exceeded the max-steps bound of '{1}' in {2:F2}% of the fair execution paths.",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
configuration.MaxUnfairSchedulingSteps, configuration.MaxUnfairSchedulingSteps,
(double)this.MaxUnfairStepsHitInFairTests / this.NumOfExploredFairSchedules * 100); (double)this.MaxUnfairStepsHitInFairTests / this.NumOfExploredFairPaths * 100);
} }
if (configuration.UserExplicitlySetMaxFairSchedulingSteps && if (configuration.UserExplicitlySetMaxFairSchedulingSteps &&
@ -515,21 +517,21 @@ namespace Microsoft.Coyote.SystematicTesting
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Hit the max-steps bound of '{1}' in {2:F2}% of the fair schedules.", "{0} Hit the max-steps bound of '{1}' in {2:F2}% of the fair execution paths.",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
configuration.MaxFairSchedulingSteps, configuration.MaxFairSchedulingSteps,
(double)this.MaxFairStepsHitInFairTests / this.NumOfExploredFairSchedules * 100); (double)this.MaxFairStepsHitInFairTests / this.NumOfExploredFairPaths * 100);
} }
} }
if (this.NumOfExploredUnfairSchedules > 0) if (this.NumOfExploredUnfairPaths > 0)
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Number of scheduling decisions in unfair terminating schedules: {1} (min), {2} (avg), {3} (max).", "{0} Number of scheduling decisions in unfair terminating execution paths: {1} (min), {2} (avg), {3} (max).",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
this.MinExploredUnfairSteps < 0 ? 0 : this.MinExploredUnfairSteps, this.MinExploredUnfairSteps < 0 ? 0 : this.MinExploredUnfairSteps,
this.TotalExploredUnfairSteps / this.NumOfExploredUnfairSchedules, this.TotalExploredUnfairSteps / this.NumOfExploredUnfairPaths,
this.MaxExploredUnfairSteps < 0 ? 0 : this.MaxExploredUnfairSteps); this.MaxExploredUnfairSteps < 0 ? 0 : this.MaxExploredUnfairSteps);
if (configuration.MaxUnfairSchedulingSteps > 0 && if (configuration.MaxUnfairSchedulingSteps > 0 &&
@ -537,10 +539,10 @@ namespace Microsoft.Coyote.SystematicTesting
{ {
report.AppendLine(); report.AppendLine();
report.AppendFormat( report.AppendFormat(
"{0} Hit the max-steps bound of '{1}' in {2:F2}% of the unfair schedules.", "{0} Hit the max-steps bound of '{1}' in {2:F2}% of the unfair execution paths.",
prefix.Equals("...") ? "....." : prefix, prefix.Equals("...") ? "....." : prefix,
configuration.MaxUnfairSchedulingSteps, configuration.MaxUnfairSchedulingSteps,
(double)this.MaxUnfairStepsHitInUnfairTests / this.NumOfExploredUnfairSchedules * 100); (double)this.MaxUnfairStepsHitInUnfairTests / this.NumOfExploredUnfairPaths * 100);
} }
} }

Просмотреть файл

@ -33,9 +33,9 @@ namespace Microsoft.Coyote.SystematicTesting
public TestSettings Settings { get; set; } public TestSettings Settings { get; set; }
/// <summary> /// <summary>
/// The controlled decisions of this trace. /// The execution steps in this trace.
/// </summary> /// </summary>
public List<string> Decisions { get; set; } public List<string> Steps { get; set; }
/// <summary> /// <summary>
/// Constructs a <see cref="TraceReport"/> from the specified <see cref="OperationScheduler"/> /// Constructs a <see cref="TraceReport"/> from the specified <see cref="OperationScheduler"/>
@ -110,35 +110,47 @@ namespace Microsoft.Coyote.SystematicTesting
configuration.UncontrolledConcurrencyResolutionAttempts = report.Settings.UncontrolledConcurrencyResolutionAttempts; configuration.UncontrolledConcurrencyResolutionAttempts = report.Settings.UncontrolledConcurrencyResolutionAttempts;
configuration.UncontrolledConcurrencyResolutionDelay = report.Settings.UncontrolledConcurrencyResolutionDelay; configuration.UncontrolledConcurrencyResolutionDelay = report.Settings.UncontrolledConcurrencyResolutionDelay;
foreach (var decision in report.Decisions) for (int idx = 0; idx < report.Steps.Count; idx++)
{ {
string[] tokens = decision.Split(','); string[] tokens = report.Steps[idx].Split(',');
string kindToken = tokens[0];
string spToken = tokens[1];
// The current operation token is of the form 'op(id:seqId)'.
string opToken = tokens[0];
string[] opTokens = opToken.Substring(3, opToken.Length - 4).Split(':');
ulong opId = ulong.Parse(opTokens[0]);
ulong opSeqId = ulong.Parse(opTokens[1]);
string decisionToken = tokens[1];
if (decisionToken.StartsWith("sp("))
{
#if NET || NETCOREAPP3_1 #if NET || NETCOREAPP3_1
SchedulingPointType sp = Enum.Parse<SchedulingPointType>(spToken.Substring(3, spToken.Length - 4)); SchedulingPointType sp = Enum.Parse<SchedulingPointType>(decisionToken.Substring(
3, decisionToken.Length - 4));
#else #else
SchedulingPointType sp = (SchedulingPointType)Enum.Parse(typeof(SchedulingPointType), spToken.Substring(3, spToken.Length - 4)); SchedulingPointType sp = (SchedulingPointType)Enum.Parse(typeof(SchedulingPointType),
decisionToken.Substring(3, decisionToken.Length - 4));
#endif #endif
if (kindToken.StartsWith("op("))
{ // The next operation token is of the form 'next(id:seqId)'.
ulong id = ulong.Parse(kindToken.Substring(3, kindToken.Length - 4)); string nextToken = tokens[2];
trace.AddSchedulingChoice(id, sp); string[] nextTokens = nextToken.Substring(5, nextToken.Length - 6).Split(':');
ulong nextId = ulong.Parse(nextTokens[0]);
ulong nextSeqId = ulong.Parse(nextTokens[1]);
trace.AddSchedulingDecision(opId, opSeqId, sp, nextId, nextSeqId);
} }
else if (kindToken.StartsWith("bool(")) else if (decisionToken.StartsWith("bool("))
{ {
bool value = bool.Parse(kindToken.Substring(5, kindToken.Length - 6)); bool value = bool.Parse(decisionToken.Substring(5, decisionToken.Length - 6));
trace.AddNondeterministicBooleanChoice(value, sp); trace.AddNondeterministicBooleanDecision(opId, opSeqId, value);
} }
else if (kindToken.StartsWith("int(")) else if (decisionToken.StartsWith("int("))
{ {
int value = int.Parse(kindToken.Substring(4, kindToken.Length - 5)); int value = int.Parse(decisionToken.Substring(4, decisionToken.Length - 5));
trace.AddNondeterministicIntegerChoice(value, sp); trace.AddNondeterministicIntegerDecision(opId, opSeqId, value);
} }
else else
{ {
throw new InvalidOperationException($"Unexpected decision '{decision}'."); throw new InvalidOperationException($"Unexpected execution step '{report.Steps[idx]}'.");
} }
} }
} }
@ -151,22 +163,10 @@ namespace Microsoft.Coyote.SystematicTesting
/// </summary> /// </summary>
internal void ReportTrace(ExecutionTrace trace) internal void ReportTrace(ExecutionTrace trace)
{ {
this.Decisions = new List<string>(); this.Steps = new List<string>();
for (int idx = 0; idx < trace.Length; idx++) foreach (var step in trace)
{ {
ExecutionTrace.Step step = trace[idx]; this.Steps.Add(step.ToString());
if (step.Kind == ExecutionTrace.DecisionKind.SchedulingChoice)
{
this.Decisions.Add($"op({step.ScheduledOperationId}),sp({step.SchedulingPoint})");
}
else if (step.BooleanChoice != null)
{
this.Decisions.Add($"bool({step.BooleanChoice.Value}),sp({step.SchedulingPoint})");
}
else
{
this.Decisions.Add($"int({step.IntegerChoice.Value}),sp({step.SchedulingPoint})");
}
} }
} }

Просмотреть файл

@ -181,7 +181,7 @@ namespace Microsoft.Coyote.SystematicTesting
error += " Possible methods are:" + Environment.NewLine; error += " Possible methods are:" + Environment.NewLine;
var possibleMethods = filteredTestMethods?.Count > 1 ? filteredTestMethods : testMethods; var possibleMethods = filteredTestMethods?.Count > 1 ? filteredTestMethods : testMethods;
for (int idx = 0; idx < possibleMethods.Count; idx++) for (int idx = 0; idx < possibleMethods.Count; ++idx)
{ {
var mi = possibleMethods[idx]; var mi = possibleMethods[idx];
error += string.Format(" {0}.{1}", mi.DeclaringType.FullName, mi.Name); error += string.Format(" {0}.{1}", mi.DeclaringType.FullName, mi.Name);

Просмотреть файл

@ -15,116 +15,115 @@ namespace Microsoft.Coyote.Runtime.Tests
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
public void TestExecutionTraceAddSchedulingChoices() public void TestExecutionTraceAddSchedulingDecisions()
{ {
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(2, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
trace.AddSchedulingChoice(3, SchedulingPointType.Default); trace.AddSchedulingDecision(1, 1, SchedulingPointType.Default, 3, 3);
trace.AddSchedulingChoice(1, SchedulingPointType.Default); trace.AddSchedulingDecision(2, 2, SchedulingPointType.Default, 1, 1);
trace.AddSchedulingChoice(2, SchedulingPointType.Default); trace.AddSchedulingDecision(1, 1, SchedulingPointType.Default, 2, 2);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 5); Assert.True(trace.Length is 5);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[0] is ExecutionTrace.SchedulingStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Value is 0);
Assert.True((trace[0] as ExecutionTrace.SchedulingStep).SequenceId is 0);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[1] is ExecutionTrace.SchedulingStep);
Assert.True(trace[1].ScheduledOperationId is 2); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Value is 2);
Assert.True((trace[1] as ExecutionTrace.SchedulingStep).SequenceId is 2);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[2] is ExecutionTrace.SchedulingStep);
Assert.True(trace[2].ScheduledOperationId is 3); Assert.True((trace[2] as ExecutionTrace.SchedulingStep).Current is 1);
Assert.True(!trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 1);
Assert.True(!trace[2].IntegerChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.SchedulingStep).Value is 3);
Assert.True((trace[2] as ExecutionTrace.SchedulingStep).SequenceId is 3);
Assert.True(trace[3].Index is 3); Assert.True(trace[3].Index is 3);
Assert.True(trace[3].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[3] is ExecutionTrace.SchedulingStep);
Assert.True(trace[3].ScheduledOperationId is 1); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Current is 2);
Assert.True(!trace[3].BooleanChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 2);
Assert.True(!trace[3].IntegerChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Value is 1);
Assert.True((trace[3] as ExecutionTrace.SchedulingStep).SequenceId is 1);
Assert.True(trace[4].Index is 4); Assert.True(trace[4].Index is 4);
Assert.True(trace[4].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[4] is ExecutionTrace.SchedulingStep);
Assert.True(trace[4].ScheduledOperationId is 2); Assert.True((trace[4] as ExecutionTrace.SchedulingStep).Current is 1);
Assert.True(!trace[4].BooleanChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 1);
Assert.True(!trace[4].IntegerChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.SchedulingStep).Value is 2);
Assert.True((trace[4] as ExecutionTrace.SchedulingStep).SequenceId is 2);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
public void TestExecutionTraceAddNondeterministicBooleanChoices() public void TestExecutionTraceAddNondeterministicBooleanDecisions()
{ {
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(0, 0, true);
trace.AddNondeterministicBooleanChoice(false, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(0, 0, false);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(0, 0, true);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[0] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.BooleanChoiceStep).Current is 0);
Assert.True(trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[0].BooleanChoice.Value is true); Assert.True((trace[0] as ExecutionTrace.BooleanChoiceStep).Value is true);
Assert.True(!trace[0].IntegerChoice.HasValue);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[1] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[1].ScheduledOperationId is 0); Assert.True((trace[1] as ExecutionTrace.BooleanChoiceStep).Current is 0);
Assert.True(trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[1].BooleanChoice.Value is false); Assert.True((trace[1] as ExecutionTrace.BooleanChoiceStep).Value is false);
Assert.True(!trace[1].IntegerChoice.HasValue);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[2] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[2].ScheduledOperationId is 0); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Current is 0);
Assert.True(trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[2].BooleanChoice.Value is true); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Value is true);
Assert.True(!trace[2].IntegerChoice.HasValue);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
public void TestExecutionTraceAddNondeterministicIntegerChoices() public void TestExecutionTraceAddNondeterministicIntegerDecisions()
{ {
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddNondeterministicIntegerChoice(3, SchedulingPointType.Default); trace.AddNondeterministicIntegerDecision(0, 0, 3);
trace.AddNondeterministicIntegerChoice(7, SchedulingPointType.Default); trace.AddNondeterministicIntegerDecision(0, 0, 7);
trace.AddNondeterministicIntegerChoice(4, SchedulingPointType.Default); trace.AddNondeterministicIntegerDecision(0, 0, 4);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[0] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.IntegerChoiceStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.IntegerChoiceStep).Value is 3);
Assert.True(trace[0].IntegerChoice.Value is 3);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[1] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[1].ScheduledOperationId is 0); Assert.True((trace[1] as ExecutionTrace.IntegerChoiceStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.IntegerChoiceStep).Value is 7);
Assert.True(trace[1].IntegerChoice.Value is 7);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[2] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[2].ScheduledOperationId is 0); Assert.True((trace[2] as ExecutionTrace.IntegerChoiceStep).Current is 0);
Assert.True(!trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[2].IntegerChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.IntegerChoiceStep).Value is 4);
Assert.True(trace[2].IntegerChoice.Value is 4);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
@ -133,45 +132,46 @@ namespace Microsoft.Coyote.Runtime.Tests
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(2, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(2, 2, true);
trace.AddSchedulingChoice(1, SchedulingPointType.Default); trace.AddSchedulingDecision(2, 2, SchedulingPointType.Default, 1, 1);
trace.AddNondeterministicIntegerChoice(5, SchedulingPointType.Default); trace.AddNondeterministicIntegerDecision(1, 1, 5);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 5); Assert.True(trace.Length is 5);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[0] is ExecutionTrace.SchedulingStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Value is 0);
Assert.True((trace[0] as ExecutionTrace.SchedulingStep).SequenceId is 0);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[1] is ExecutionTrace.SchedulingStep);
Assert.True(trace[1].ScheduledOperationId is 2); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Value is 2);
Assert.True((trace[1] as ExecutionTrace.SchedulingStep).SequenceId is 2);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[2] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[2].ScheduledOperationId is 0); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Current is 2);
Assert.True(trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 2);
Assert.True(trace[2].BooleanChoice.Value is true); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Value is true);
Assert.True(!trace[2].IntegerChoice.HasValue);
Assert.True(trace[3].Index is 3); Assert.True(trace[3].Index is 3);
Assert.True(trace[3].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[3] is ExecutionTrace.SchedulingStep);
Assert.True(trace[3].ScheduledOperationId is 1); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Current is 2);
Assert.True(!trace[3].BooleanChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 2);
Assert.True(!trace[3].IntegerChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Value is 1);
Assert.True((trace[3] as ExecutionTrace.SchedulingStep).SequenceId is 1);
Assert.True(trace[4].Index is 4); Assert.True(trace[4].Index is 4);
Assert.True(trace[4].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[4] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[4].ScheduledOperationId is 0); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).Current is 1);
Assert.True(!trace[4].BooleanChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 1);
Assert.True(trace[4].IntegerChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).Value is 5);
Assert.True(trace[4].IntegerChoice.Value is 5);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
@ -180,17 +180,17 @@ namespace Microsoft.Coyote.Runtime.Tests
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(2, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(2, 2, true);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
ExecutionTrace other = ExecutionTrace.Create(); ExecutionTrace other = ExecutionTrace.Create();
Assert.True(other.Length is 0); Assert.True(other.Length is 0);
other.AddSchedulingChoice(0, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
other.AddSchedulingChoice(2, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
this.LogTrace(other); this.LogTrace(other);
Assert.True(other.Length is 2); Assert.True(other.Length is 2);
@ -199,23 +199,24 @@ namespace Microsoft.Coyote.Runtime.Tests
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[0] is ExecutionTrace.SchedulingStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Value is 0);
Assert.True((trace[0] as ExecutionTrace.SchedulingStep).SequenceId is 0);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[1] is ExecutionTrace.SchedulingStep);
Assert.True(trace[1].ScheduledOperationId is 2); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Value is 2);
Assert.True((trace[1] as ExecutionTrace.SchedulingStep).SequenceId is 2);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[2] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[2].ScheduledOperationId is 0); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Current is 2);
Assert.True(trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 2);
Assert.True(trace[2].BooleanChoice.Value is true); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Value is true);
Assert.True(!trace[2].IntegerChoice.HasValue);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
@ -224,20 +225,20 @@ namespace Microsoft.Coyote.Runtime.Tests
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(2, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(2, 2, true);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
ExecutionTrace other = ExecutionTrace.Create(); ExecutionTrace other = ExecutionTrace.Create();
Assert.True(other.Length is 0); Assert.True(other.Length is 0);
other.AddSchedulingChoice(0, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
other.AddSchedulingChoice(2, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
other.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); other.AddNondeterministicBooleanDecision(2, 2, true);
other.AddSchedulingChoice(1, SchedulingPointType.Default); other.AddSchedulingDecision(2, 2, SchedulingPointType.Default, 1, 1);
other.AddNondeterministicIntegerChoice(5, SchedulingPointType.Default); other.AddNondeterministicIntegerDecision(1, 1, 5);
this.LogTrace(other); this.LogTrace(other);
Assert.True(other.Length is 5); Assert.True(other.Length is 5);
@ -246,36 +247,37 @@ namespace Microsoft.Coyote.Runtime.Tests
Assert.True(trace.Length is 5); Assert.True(trace.Length is 5);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[0] is ExecutionTrace.SchedulingStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Value is 0);
Assert.True((trace[0] as ExecutionTrace.SchedulingStep).SequenceId is 0);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[1] is ExecutionTrace.SchedulingStep);
Assert.True(trace[1].ScheduledOperationId is 2); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Value is 2);
Assert.True((trace[1] as ExecutionTrace.SchedulingStep).SequenceId is 2);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[2] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[2].ScheduledOperationId is 0); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Current is 2);
Assert.True(trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 2);
Assert.True(trace[2].BooleanChoice.Value is true); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Value is true);
Assert.True(!trace[2].IntegerChoice.HasValue);
Assert.True(trace[3].Index is 3); Assert.True(trace[3].Index is 3);
Assert.True(trace[3].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[3] is ExecutionTrace.SchedulingStep);
Assert.True(trace[3].ScheduledOperationId is 1); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Current is 2);
Assert.True(!trace[3].BooleanChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 2);
Assert.True(!trace[3].IntegerChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Value is 1);
Assert.True((trace[3] as ExecutionTrace.SchedulingStep).SequenceId is 1);
Assert.True(trace[4].Index is 4); Assert.True(trace[4].Index is 4);
Assert.True(trace[4].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[4] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[4].ScheduledOperationId is 0); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).Current is 1);
Assert.True(!trace[4].BooleanChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 1);
Assert.True(trace[4].IntegerChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).Value is 5);
Assert.True(trace[4].IntegerChoice.Value is 5);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
@ -284,9 +286,9 @@ namespace Microsoft.Coyote.Runtime.Tests
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(3, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 3, 3);
trace.AddNondeterministicBooleanChoice(false, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(3, 3, false);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
@ -305,17 +307,17 @@ namespace Microsoft.Coyote.Runtime.Tests
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(3, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 3, 3);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(3, 3, true);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
ExecutionTrace other = ExecutionTrace.Create(); ExecutionTrace other = ExecutionTrace.Create();
Assert.True(other.Length is 0); Assert.True(other.Length is 0);
other.AddSchedulingChoice(0, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
other.AddNondeterministicIntegerChoice(5, SchedulingPointType.Default); other.AddNondeterministicIntegerDecision(0, 0, 5);
this.LogTrace(other); this.LogTrace(other);
Assert.True(other.Length is 2); Assert.True(other.Length is 2);
@ -324,17 +326,17 @@ namespace Microsoft.Coyote.Runtime.Tests
Assert.True(trace.Length is 2); Assert.True(trace.Length is 2);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[0] is ExecutionTrace.SchedulingStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Value is 0);
Assert.True((trace[0] as ExecutionTrace.SchedulingStep).SequenceId is 0);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[1] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[1].ScheduledOperationId is 0); Assert.True((trace[1] as ExecutionTrace.IntegerChoiceStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 0);
Assert.True(trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.IntegerChoiceStep).Value is 5);
Assert.True(trace[1].IntegerChoice.Value is 5);
} }
[Fact(Timeout = 5000)] [Fact(Timeout = 5000)]
@ -343,20 +345,20 @@ namespace Microsoft.Coyote.Runtime.Tests
ExecutionTrace trace = ExecutionTrace.Create(); ExecutionTrace trace = ExecutionTrace.Create();
Assert.True(trace.Length is 0); Assert.True(trace.Length is 0);
trace.AddSchedulingChoice(0, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
trace.AddSchedulingChoice(2, SchedulingPointType.Default); trace.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 2, 2);
trace.AddNondeterministicBooleanChoice(true, SchedulingPointType.Default); trace.AddNondeterministicBooleanDecision(2, 2, true);
this.LogTrace(trace); this.LogTrace(trace);
Assert.True(trace.Length is 3); Assert.True(trace.Length is 3);
ExecutionTrace other = ExecutionTrace.Create(); ExecutionTrace other = ExecutionTrace.Create();
Assert.True(other.Length is 0); Assert.True(other.Length is 0);
other.AddSchedulingChoice(0, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 0, 0);
other.AddSchedulingChoice(3, SchedulingPointType.Default); other.AddSchedulingDecision(0, 0, SchedulingPointType.Default, 3, 3);
other.AddNondeterministicBooleanChoice(false, SchedulingPointType.Default); other.AddNondeterministicBooleanDecision(3, 3, false);
other.AddSchedulingChoice(1, SchedulingPointType.Default); other.AddSchedulingDecision(3, 3, SchedulingPointType.Default, 1, 1);
other.AddNondeterministicIntegerChoice(5, SchedulingPointType.Default); other.AddNondeterministicIntegerDecision(1, 1, 5);
this.LogTrace(other); this.LogTrace(other);
Assert.True(other.Length is 5); Assert.True(other.Length is 5);
@ -365,36 +367,37 @@ namespace Microsoft.Coyote.Runtime.Tests
Assert.True(trace.Length is 5); Assert.True(trace.Length is 5);
Assert.True(trace[0].Index is 0); Assert.True(trace[0].Index is 0);
Assert.True(trace[0].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[0] is ExecutionTrace.SchedulingStep);
Assert.True(trace[0].ScheduledOperationId is 0); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[0].BooleanChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[0].IntegerChoice.HasValue); Assert.True((trace[0] as ExecutionTrace.SchedulingStep).Value is 0);
Assert.True((trace[0] as ExecutionTrace.SchedulingStep).SequenceId is 0);
Assert.True(trace[1].Index is 1); Assert.True(trace[1].Index is 1);
Assert.True(trace[1].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[1] is ExecutionTrace.SchedulingStep);
Assert.True(trace[1].ScheduledOperationId is 3); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Current is 0);
Assert.True(!trace[1].BooleanChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 0);
Assert.True(!trace[1].IntegerChoice.HasValue); Assert.True((trace[1] as ExecutionTrace.SchedulingStep).Value is 3);
Assert.True((trace[1] as ExecutionTrace.SchedulingStep).SequenceId is 3);
Assert.True(trace[2].Index is 2); Assert.True(trace[2].Index is 2);
Assert.True(trace[2].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[2] is ExecutionTrace.BooleanChoiceStep);
Assert.True(trace[2].ScheduledOperationId is 0); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Current is 3);
Assert.True(trace[2].BooleanChoice.HasValue); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).CurrentSequenceId is 3);
Assert.True(trace[2].BooleanChoice.Value is false); Assert.True((trace[2] as ExecutionTrace.BooleanChoiceStep).Value is false);
Assert.True(!trace[2].IntegerChoice.HasValue);
Assert.True(trace[3].Index is 3); Assert.True(trace[3].Index is 3);
Assert.True(trace[3].Kind is ExecutionTrace.DecisionKind.SchedulingChoice); Assert.True(trace[3] is ExecutionTrace.SchedulingStep);
Assert.True(trace[3].ScheduledOperationId is 1); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Current is 3);
Assert.True(!trace[3].BooleanChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).CurrentSequenceId is 3);
Assert.True(!trace[3].IntegerChoice.HasValue); Assert.True((trace[3] as ExecutionTrace.SchedulingStep).Value is 1);
Assert.True((trace[3] as ExecutionTrace.SchedulingStep).SequenceId is 1);
Assert.True(trace[4].Index is 4); Assert.True(trace[4].Index is 4);
Assert.True(trace[4].Kind is ExecutionTrace.DecisionKind.NondeterministicChoice); Assert.True(trace[4] is ExecutionTrace.IntegerChoiceStep);
Assert.True(trace[4].ScheduledOperationId is 0); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).Current is 1);
Assert.True(!trace[4].BooleanChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).CurrentSequenceId is 1);
Assert.True(trace[4].IntegerChoice.HasValue); Assert.True((trace[4] as ExecutionTrace.IntegerChoiceStep).Value is 5);
Assert.True(trace[4].IntegerChoice.Value is 5);
} }
private void LogTrace(ExecutionTrace trace) private void LogTrace(ExecutionTrace trace)

Просмотреть файл

@ -80,11 +80,11 @@ namespace Microsoft.Coyote.Runtime.Tests.Logging
"[coyote::report] Testing statistics:", "[coyote::report] Testing statistics:",
"[coyote::report] Found 2 bugs.", "[coyote::report] Found 2 bugs.",
"[coyote::report] Scheduling statistics:", "[coyote::report] Scheduling statistics:",
"[coyote::report] Explored 2 schedules: 2 fair and 0 unfair.", "[coyote::report] Explored 2 execution paths: 2 fair, 0 unfair, 1 unique.",
"[coyote::report] Found 100.00% buggy schedules.", "[coyote::report] Found 100.00% buggy execution paths.",
"[coyote::report] Controlled 2 operations: 1 (), 1 (), 1 ().", "[coyote::report] Controlled 2 operations: 1 (), 1 (), 1 (), 1 ().",
"[coyote::report] Degree of operation grouping: 1 (), 1 (), 1 ().", "[coyote::report] Degree of operation grouping: 1 (), 1 (), 1 ().",
"[coyote::report] Number of scheduling decisions in fair terminating schedules: 0 (), 0 (), 0 ()."); "[coyote::report] Number of scheduling decisions in fair terminating execution paths: 0 (), 0 (), 0 ().");
this.TestOutput.WriteLine($"Observed (length: {observed.Length}):"); this.TestOutput.WriteLine($"Observed (length: {observed.Length}):");
this.TestOutput.WriteLine(observed); this.TestOutput.WriteLine(observed);
Assert.Equal(expectedObserved, observed); Assert.Equal(expectedObserved, observed);
@ -158,11 +158,11 @@ namespace Microsoft.Coyote.Runtime.Tests.Logging
"[coyote::report] Testing statistics:", "[coyote::report] Testing statistics:",
"[coyote::report] Found 2 bugs.", "[coyote::report] Found 2 bugs.",
"[coyote::report] Scheduling statistics:", "[coyote::report] Scheduling statistics:",
"[coyote::report] Explored 2 schedules: 2 fair and 0 unfair.", "[coyote::report] Explored 2 execution paths: 2 fair, 0 unfair, 1 unique.",
"[coyote::report] Found 100.00% buggy schedules.", "[coyote::report] Found 100.00% buggy execution paths.",
"[coyote::report] Controlled 2 operations: 1 (), 1 (), 1 ().", "[coyote::report] Controlled 2 operations: 1 (), 1 (), 1 (), 1 ().",
"[coyote::report] Degree of operation grouping: 1 (), 1 (), 1 ().", "[coyote::report] Degree of operation grouping: 1 (), 1 (), 1 ().",
"[coyote::report] Number of scheduling decisions in fair terminating schedules: 0 (), 0 (), 0 ()."); "[coyote::report] Number of scheduling decisions in fair terminating execution paths: 0 (), 0 (), 0 ().");
this.TestOutput.WriteLine($"Observed (length: {observed.Length}):"); this.TestOutput.WriteLine($"Observed (length: {observed.Length}):");
this.TestOutput.WriteLine(observed); this.TestOutput.WriteLine(observed);
Assert.Equal(expectedObserved, observed); Assert.Equal(expectedObserved, observed);
@ -232,11 +232,11 @@ namespace Microsoft.Coyote.Runtime.Tests.Logging
"[coyote::report] Testing statistics:", "[coyote::report] Testing statistics:",
"[coyote::report] Found 2 bugs.", "[coyote::report] Found 2 bugs.",
"[coyote::report] Scheduling statistics:", "[coyote::report] Scheduling statistics:",
"[coyote::report] Explored 2 schedules: 2 fair and 0 unfair.", "[coyote::report] Explored 2 execution paths: 2 fair, 0 unfair, 1 unique.",
"[coyote::report] Found 100.00% buggy schedules.", "[coyote::report] Found 100.00% buggy execution paths.",
"[coyote::report] Controlled 2 operations: 1 (), 1 (), 1 ().", "[coyote::report] Controlled 2 operations: 1 (), 1 (), 1 (), 1 ().",
"[coyote::report] Degree of operation grouping: 1 (), 1 (), 1 ().", "[coyote::report] Degree of operation grouping: 1 (), 1 (), 1 ().",
"[coyote::report] Number of scheduling decisions in fair terminating schedules: 0 (), 0 (), 0 ()."); "[coyote::report] Number of scheduling decisions in fair terminating execution paths: 0 (), 0 (), 0 ().");
this.TestOutput.WriteLine($"Observed (length: {observed.Length}):"); this.TestOutput.WriteLine($"Observed (length: {observed.Length}):");
this.TestOutput.WriteLine(observed); this.TestOutput.WriteLine(observed);
Assert.Equal(expectedObserved, observed); Assert.Equal(expectedObserved, observed);