Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ words:
- fileassert
- FileAssert
- filepart
- selftest
- testname
- TMPL
- triaging
Expand Down
59 changes: 56 additions & 3 deletions .reviewmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,84 @@ evidence-source:
# Each review-set groups requirements, source, and tests for a coherent software unit
# so that an AI-assisted review can verify consistency across the full evidence chain.
reviews:
# System review - end-to-end behavior and design overview
- id: FileAssert-System
title: Review of FileAssert System
paths:
- "docs/reqstream/fileassert-system.yaml"
- "docs/design/introduction.md"
- "docs/design/system.md"
- "test/**/IntegrationTests.cs"

# Subsystem reviews - one per subsystem
- id: FileAssert-Cli
title: Review of FileAssert Cli Subsystem
paths:
- "docs/reqstream/subsystem-cli.yaml"
- "docs/design/cli.md"
- "test/**/CliSubsystemTests.cs"

- id: FileAssert-Configuration
title: Review of FileAssert Configuration Subsystem
paths:
- "docs/reqstream/subsystem-configuration.yaml"
- "docs/design/configuration.md"
- "test/**/ConfigurationSubsystemTests.cs"

- id: FileAssert-Modeling
title: Review of FileAssert Modeling Subsystem
paths:
- "docs/reqstream/subsystem-modeling.yaml"
- "docs/design/modeling.md"
- "test/**/ModelingSubsystemTests.cs"

- id: FileAssert-Utilities
title: Review of FileAssert Utilities Subsystem
paths:
- "docs/reqstream/subsystem-utilities.yaml"
- "docs/design/utilities.md"
- "test/**/UtilitiesSubsystemTests.cs"

- id: FileAssert-SelfTest
title: Review of FileAssert SelfTest Subsystem
paths:
- "docs/reqstream/subsystem-selftest.yaml"
- "docs/design/selftest.md"
- "test/**/SelfTestSubsystemTests.cs"

# Software unit reviews - one per class
- id: FileAssert-Context
title: Review of FileAssert Context Unit
paths:
- "docs/reqstream/unit-context.yaml"
- "docs/design/context.md"
- "src/**/Context.cs"
- "test/**/ContextTests.cs"
- "test/**/ContextNewPropertiesTests.cs"

- id: FileAssert-Program
title: Review of FileAssert Program Unit
paths:
- "docs/reqstream/unit-program.yaml"
- "docs/design/program.md"
- "src/**/Program.cs"
- "test/**/ProgramTests.cs"
- "test/**/IntegrationTests.cs"
- "test/**/Runner.cs"
- "test/**/AssemblyInfo.cs"

- id: FileAssert-Validation
title: Review of FileAssert Validation Unit
paths:
- "docs/reqstream/unit-validation.yaml"
- "docs/design/validation.md"
- "src/**/Validation.cs"
- "test/**/ValidationTests.cs"

- id: FileAssert-PathHelpers
title: Review of FileAssert PathHelpers Unit
paths:
- "docs/reqstream/unit-path-helpers.yaml"
- "docs/design/path-helpers.md"
- "src/**/PathHelpers.cs"
- "test/**/PathHelpersTests.cs"

Expand All @@ -61,7 +110,6 @@ reviews:
- "docs/reqstream/unit-file-assert-rule.yaml"
- "docs/design/file-assert-rule.md"
- "src/**/FileAssertRule.cs"
- "src/**/FileAssertData.cs"
- "test/**/FileAssertRuleTests.cs"

- id: FileAssert-FileAssertFile
Expand All @@ -87,7 +135,12 @@ reviews:
- "docs/design/file-assert-config.md"
- "src/**/FileAssertConfig.cs"
- "test/**/FileAssertConfigTests.cs"
- "test/**/ContextNewPropertiesTests.cs"

- id: FileAssert-FileAssertData
title: Review of FileAssert FileAssertData Unit
paths:
- "docs/design/file-assert-data.md"
- "src/**/FileAssertData.cs"

# Platform and OTS dependency reviews
- id: Platform-Support
Expand Down
40 changes: 40 additions & 0 deletions docs/design/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Cli Subsystem Design

## Overview

The Cli subsystem is responsible for translating the raw command-line argument array into a
structured, immutable context object that the rest of the tool uses for output, configuration,
and execution decisions.

## Subsystem Contents

| Unit | File | Responsibility |
| :-------- | :------------ | :-------------------------------------------------------- |
| `Context` | `Context.cs` | Parses arguments and owns all I/O operations. |

## Subsystem Responsibilities

- Parse all supported flags (`--version`, `--help`, `--silent`, `--validate`, `--log`,
`--results`, `--config`) and positional filter arguments.
- Reject unknown or malformed arguments with a descriptive `ArgumentException`.
- Open and manage a log file when `--log` is specified.
- Write output to stdout and the log file; write errors to stderr and the log file.
- Expose an exit code that reflects whether any errors have been reported.

## Interactions with Other Subsystems

| Consumer | Usage |
| :---------------- | :------------------------------------------------------------------- |
| Program | Creates a `Context` and passes it to all downstream operations. |
| Configuration | Receives a `Context` to report errors and write progress output. |
| Modeling | Receives a `Context` to write error messages for assertion failures. |
| SelfTest | Receives a `Context` to write validation results and errors. |

## Design Decisions

- **Immutable context object**: Properties are set once via `private init` accessors, preventing
accidental mutation after the context is created.
- **Internal ArgumentParser helper**: Argument parsing is encapsulated in a private nested
class, keeping the public `Context` interface focused on output and state rather than parsing.
- **AutoFlush log writer**: The log file stream is opened with `AutoFlush = true` so that log
entries are written to disk immediately, even if the process terminates unexpectedly.
58 changes: 58 additions & 0 deletions docs/design/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Configuration Subsystem Design

## Overview

The Configuration subsystem is responsible for reading the YAML test-suite configuration file
and constructing the domain object hierarchy that drives test execution. It owns the data
transfer objects used during deserialization and the top-level configuration class that loads
and runs the tests.

## Subsystem Contents

| Unit | File | Responsibility |
| :----------------- | :--------------------- | :---------------------------------------------------------- |
| `FileAssertConfig` | `FileAssertConfig.cs` | Loads the YAML file and runs the filtered test suite. |
| `FileAssertData` | `FileAssertData.cs` | Data transfer objects for YAML deserialization. |

## Subsystem Responsibilities

- Read and deserialize a YAML configuration file using YamlDotNet.
- Tolerate unknown YAML properties for forward compatibility.
- Construct the full `FileAssertTest → FileAssertFile → FileAssertRule` hierarchy from the
deserialized data.
- Resolve the base directory for glob patterns from the configuration file path.
- Filter tests by name or tag before execution.

## Interactions with Other Subsystems

| Dependency | Usage |
| :---------- | :-------------------------------------------------------------------------- |
| Cli | Receives a `Context` to report errors and write progress output. |
| Modeling | Delegates test construction to `FileAssertTest.Create` and execution to |
| | `FileAssertTest.Run`. |

## YAML Configuration Format

The top-level YAML structure is:

```yaml
tests:
- name: "Test Name"
tags:
- tag1
files:
- pattern: "**/*.cs"
min: 1
rules:
- contains: "Copyright"
```

## Design Decisions

- **Separation of data and domain objects**: The `FileAssertData` classes are pure data holders
with no logic. The Modeling subsystem owns the domain objects built from them.
- **Forward-compatible deserialization**: `IgnoreUnmatchedProperties()` allows configuration
files to contain keys introduced in later tool versions without causing parse failures.
- **Base directory from config path**: Resolving glob patterns relative to the configuration
file location is more intuitive than the working directory, especially when the tool is
invoked from a build script in a different directory.
62 changes: 62 additions & 0 deletions docs/design/context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Context Design

## Overview

`Context` is the command-line argument parser and I/O owner for FileAssert. It translates the
raw `string[]` argument array into named properties, manages the optional log file stream, and
provides a unified interface for writing output and errors throughout the tool's execution.

## Class Structure

### Properties

| Property | Type | Description |
| :--------------------- | :---------------------- | :------------------------------------------------------------ |
| `Version` | `bool` | Set when `--version` or `-v` is present. |
| `Help` | `bool` | Set when `--help`, `-h`, or `-?` is present. |
| `Silent` | `bool` | Set when `--silent` is present. |
| `Validate` | `bool` | Set when `--validate` is present. |
| `ResultsFile` | `string?` | Path provided via `--results`, or null. |
| `ConfigFile` | `string` | Path provided via `--config`; defaults to `.fileassert.yaml`. |
| `IsConfigFileExplicit` | `bool` | True when `--config` was explicitly specified. |
| `Filters` | `IReadOnlyList<string>` | Positional arguments treated as test name or tag filters. |
| `ExitCode` | `int` | Returns `1` if any errors have been reported; otherwise `0`. |

### Factory Method

```csharp
public static Context Create(string[] args)
```

Delegates argument parsing to the private `ArgumentParser` nested class. Opens a log file if
`--log` was specified. Returns the fully initialized `Context` instance.

### Output Methods

```csharp
public void WriteLine(string message)
public void WriteError(string message)
```

`WriteLine` writes to stdout and the log file (unless `--silent` suppresses console output).
`WriteError` sets the internal error flag, writes to stderr in red (unless silent), and writes
to the log file.

### Argument Parsing

The private nested class `ArgumentParser` processes each argument in order:

- Flag arguments (starting with `--` or `-`) are matched by a `switch` statement.
- Arguments requiring a value (`--log`, `--results`, `--config`) consume the next element
from the argument array and throw `ArgumentException` if no value follows.
- Unknown flag arguments (starting with `-`) throw `ArgumentException`.
- All other arguments are accumulated in the `Filters` list.

## Design Decisions

- **Sealed with IDisposable**: The class is sealed to prevent inheritance of internal state, and
implements `IDisposable` to ensure the log file stream is always closed.
- **Factory method**: The `Create` factory method is `public` so tests and the self-validation
tests can construct a context directly without invoking `Main`.
- **Error flag over exception**: `WriteError` sets a flag rather than throwing, so the tool
completes all assertions before reporting a final failure via the exit code.
17 changes: 14 additions & 3 deletions docs/design/definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@ resource-path:
input-files:
- docs/design/title.txt
- docs/design/introduction.md
- docs/design/file-assert-rule.md
- docs/design/file-assert-file.md
- docs/design/file-assert-test.md
- docs/design/system.md
- docs/design/program.md
- docs/design/cli.md
- docs/design/context.md
- docs/design/configuration.md
- docs/design/file-assert-config.md
- docs/design/file-assert-data.md
- docs/design/modeling.md
- docs/design/file-assert-test.md
- docs/design/file-assert-file.md
- docs/design/file-assert-rule.md
- docs/design/utilities.md
- docs/design/path-helpers.md
- docs/design/selftest.md
- docs/design/validation.md
template: template.html
table-of-contents: true
number-sections: true
59 changes: 59 additions & 0 deletions docs/design/file-assert-data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# FileAssertData Design

## Overview

`FileAssertData` is the set of YAML data transfer objects (DTOs) used by YamlDotNet to
deserialize the FileAssert configuration file. Each class maps directly to a YAML structure
and is intentionally free of business logic. Domain objects are constructed from these DTOs
by the Modeling subsystem.

## Class Structure

### FileAssertRuleData

Represents a single content validation rule within a file assertion.

| Property | YAML alias | Type | Description |
| :--------- | :---------- | :-------- | :---------------------------------------------- |
| `Contains` | `contains` | `string?` | Substring that file content must contain. |
| `Matches` | `matches` | `string?` | Regular expression the file content must match. |

Exactly one property shall be set per rule. The `FileAssertRule.Create` factory enforces this.

### FileAssertFileData

Represents a file pattern assertion within a test.

| Property | YAML alias | Type | Description |
| :-------- | :--------- | :--------------------------- | :----------------------------------------------------------- |
| `Pattern` | `pattern` | `string?` | Glob pattern used to locate files. |
| `Min` | `min` | `int?` | Minimum number of matching files; null means no lower bound. |
| `Max` | `max` | `int?` | Maximum number of matching files; null means no upper bound. |
| `Rules` | `rules` | `List<FileAssertRuleData>?` | Content rules applied to each matched file. |

### FileAssertTestData

Represents a named test within the configuration.

| Property | YAML alias | Type | Description |
| :------- | :--------- | :--------------------------- | :-------------------------------------------- |
| `Name` | `name` | `string?` | Human-readable name for the test. |
| `Tags` | `tags` | `List<string>?` | Tags used for command-line filter selection. |
| `Files` | `files` | `List<FileAssertFileData>?` | File assertions belonging to this test. |

### FileAssertConfigData

Represents the top-level configuration document.

| Property | YAML alias | Type | Description |
| :------- | :--------- | :--------------------------- | :-------------------------------------------- |
| `Tests` | `tests` | `List<FileAssertTestData>?` | Tests defined in this configuration file. |

## Design Decisions

- **Nullable reference type properties**: All properties are nullable to correctly represent
absent YAML keys without throwing during deserialization.
- **No validation logic in DTOs**: Validation and construction of domain objects is the
responsibility of the factory methods in the Modeling subsystem, keeping DTOs simple.
- **YamlMember aliases**: Explicit `[YamlMember(Alias = "...")]` attributes tie each property
to its YAML key, decoupling C# naming conventions from the YAML schema.
Loading