<< All versions

Skill v1.0.0

currentTrusted Publisher100/100
microsoft/accordant/quickref
──Details
PublishedOctober 1, 2026 at 05:01 AM
Content Hashsha256:44fc6062a1123903...
Git SHA
──Files
Files (1 file, 6.3 KB)
SKILL.md6.3 KBactive
SKILL.md · 276 lines · 6.3 KB

version: "1.0.0" name: accordant-quickref description: Quick reference and cheatsheet for Accordant API - use this skill for quick syntax lookup or code snippets


Accordant Quick Reference

State Definition

csharp
[State]
public partial class MyState
{
public Dictionary<string, decimal> Balances { get; set; } = new();
public Dictionary<string, UserState> Users { get; set; } = new();
}
[State]
public partial class UserState
{
public string Name { get; set; } = string.Empty;
public List<string> Tags { get; set; } = new();
}

Create a Spec

csharp
var spec = new Spec<MyState>()
.WithJsonPrinters(); // Optional: nice logging

Define Operations

Inline Syntax

csharp
spec.Operation<TRequest, TResponse>("OperationName", (request, state) =>
{
// Return ExpectedOutcomes
});

Examples

csharp
// Simple request (single value)
spec.Operation<string, ApiResult<User>>("GetUser", (userId, state) => { ... });
// Tuple request (multiple values)
spec.Operation<(string Id, decimal Amount), ApiResult<decimal>>("Deposit", (request, state) =>
{
var (id, amount) = request; // Destructure
// ...
});
// Class-based request
spec.Operation<CreateUserRequest, ApiResult<User>>("CreateUser", (request, state) => { ... });

Expected Outcomes

Basic Expectation

csharp
Expect.That<TResponse>(response => /* predicate */)

With Explanation (Recommended)

csharp
Expect.That<ApiResult<decimal>>(
r => r.IsSuccess && r.Data == expectedValue,
$"Expected success with value {expectedValue}")

With ValidationResult

csharp
Expect.That<User>(response =>
{
if (response.Name != expected)
return ValidationResult.Invalid($"Name mismatch: {response.Name}");
return ValidationResult.Valid();
})

Exception Expectation

csharp
Expect.Throws<NotFoundException>("Resource not found")

Multiple Valid Outcomes

csharp
Expect.OneOf(
Expect.That<T>(r => /* outcome 1 */).ThenState(...),
Expect.That<T>(r => /* outcome 2 */).SameState(),
Expect.That<T>(r => /* outcome 3 */).ThenState(...)
)

State Transitions

No Change

csharp
.SameState()

State Changes

csharp
.ThenState<MyState>(nextState => nextState.Items[id] = newValue)

Response-Dependent State

csharp
.ThenState<MyState>(
(TResponse response, MyState nextState) =>
nextState.Items[response.Id] = new Item { ... },
mock: () => new TResponse { Id = Guid.NewGuid().ToString() })

Async Operations

csharp
.ThenState<MyState>(next => next.Jobs[id] = JobStatus.Pending)
.Triggers(AsyncOperation.Create<MyState>(
isTerminal: s => s.Jobs[id] != JobStatus.Pending,
transitions: new Action<MyState>[] {
next => next.Jobs[id] = JobStatus.Completed,
next => next.Jobs[id] = JobStatus.Failed
}
))

Bind Execution

csharp
spec.ExecuteWith<ApiClient>()
.Bind<TRequest, TResponse>("OperationName",
(client, request) => client.Method(request).Result)
.BindAsync<TRequest, TResponse>("AsyncOperation",
async (client, request) => await client.MethodAsync(request));

Test Generation

Define Inputs

csharp
var inputs = new InputSet
{
spec.GetOperation<string, ApiResult<User>>("CreateUser").With("alice", "Create Alice"),
spec.GetOperation<(string, decimal), ApiResult<decimal>>("Deposit").With(("alice", 100m), "Deposit 100"),
};

Generate Tests

csharp
var testCases = spec.GenerateTests(initialState, inputs, new TestGenerationOptions
{
MaxDepth = 5,
StateConstraint = state => ((MyState)state).Items.Count <= 3
});

Run Tests

csharp
var context = spec.CreateTestingContext();
context.Register(new ApiClient(httpClient));
var results = await spec.RunTests(context, initialState, testCases, new TestExecutionOptions
{
BeforeEachAsync = async _ => await ResetDatabase()
});
Assert.That(results.All(r => r.Success));

Concurrent Tests

csharp
var concurrentTestCases = spec.GenerateConcurrentTests(initialState, inputs,
new TestGenerationOptions { MaxDepth = 4 });
var results = await spec.RunTests(context, initialState, concurrentTestCases,
new TestExecutionOptions { ... });

Manual Conformance Testing

csharp
var stateProfile = new StateProfile(initialState);
var response = await client.CreateUser("alice");
(bool isValid, string message, stateProfile) =
spec.Allows(createUserOp, "alice", response, stateProfile);
Assert.IsTrue(isValid, message);

Visualization

csharp
var dot = spec.VisualizeStateSpace(initialState, inputs, options);
File.WriteAllText("graph.dot", dot);
// Convert: dot -Tpng graph.dot -o graph.png

TestGenerationOptions

OptionTypeDefaultDescription
MaxDepthint5Max sequence length
StateConstraintFunc<State, bool>nullPrune states
MaxConcurrencyLevelint3Concurrent ops
SequentialTestCaseAlgorithmdelegateStateCoverageWalk algorithm

Test Case Algorithms

csharp
// State coverage (default)
SequentialTestCaseAlgorithms.StateCoverage
// Transition coverage
SequentialTestCaseAlgorithms.CreateTransitionCoverage(maxSequenceLength: 4)
// Random walk
SequentialTestCaseAlgorithms.CreateRandomWalk(numberOfWalks: 100, maxWalkLength: 8, seed: 42)

Common Operation Pattern

csharp
spec.Operation<(string Id, decimal Amount), ApiResult<decimal>>("Withdraw", (request, state) =>
{
var (accountId, amount) = request;
// Guard 1: Resource exists?
if (!state.Accounts.TryGetValue(accountId, out var balance))
return Expect.That<ApiResult<decimal>>(r => r.IsNotFound, "Account not found")
.SameState();
// Guard 2: Business rule
if (balance < amount)
return Expect.That<ApiResult<decimal>>(r => r.IsBadRequest, "Insufficient funds")
.SameState();
// Success path
var newBalance = balance - amount;
return Expect.That<ApiResult<decimal>>(
r => r.IsSuccess && r.Data == newBalance,
$"Expected new balance {newBalance}")
.ThenState<BankState>(next => next.Accounts[accountId] = newBalance);
});

Namespace

csharp
using Microsoft.Accordant;

NuGet Package

bash
dotnet add package Microsoft.Accordant
All versions