Skip to content

Commit d51bc38

Browse files
feat: Update folder structure and namespaces to match design documentation (#12)
* Initial plan * feat: update folder structure, namespaces, design docs, and requirements - Move source files into Cli/, Configuration/, Modeling/, Utilities/, SelfTest/ subsystems - Update namespaces to match folder hierarchy (DemaConsulting.FileAssert.{Subsystem}) - Mirror test structure in test project with matching namespaces - Add using directives for cross-namespace references - Add system.md, subsystem and unit design docs (cli, configuration, modeling, utilities, selftest, program, context, file-assert-data, path-helpers, validation) - Update docs/design/definition.yaml to include all new docs - Add subsystem requirements YAML files (cli, configuration, modeling, utilities, selftest) - Update requirements.yaml to include subsystem requirements - Add subsystem integration test classes for each subsystem - Add selftest to cspell dictionary Agent-Logs-Url: https://github.com/demaconsulting/FileAssert/sessions/fa91af23-9344-4182-aa65-6d8b99d0db2e Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> * feat: add system requirements, update review-sets - Add docs/reqstream/fileassert-system.yaml with system-level requirements - Add two new integration tests for end-to-end config execution (pass/fail) - Update requirements.yaml to include system requirements at top - Update .reviewmark.yaml with complete review-set structure: - FileAssert-System (system requirements, design intro/system, integration tests) - FileAssert-Cli/Configuration/Modeling/Utilities/SelfTest subsystem reviews - Updated unit reviews with new design docs and corrected file groupings - FileAssert-FileAssertData review for the new data design doc - Moved ContextNewPropertiesTests.cs from FileAssert-FileAssertConfig to FileAssert-Context - Moved IntegrationTests.cs from FileAssert-Program to FileAssert-System Agent-Logs-Url: https://github.com/demaconsulting/FileAssert/sessions/09aae50d-3d67-4a2c-84ef-dfe80449ee7b Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> * fix: explicitly scope context disposal before file/directory operations Use explicit `using (var context = ...) { }` braces in SelfTestSubsystemTests and CliSubsystemTests so the log file handle is fully released before: - File.ReadAllText reads the log content - tempDir.Delete(recursive: true) deletes the temp directory Prevents 'file in use' errors on Windows where handles are not immediately released after IDisposable.Dispose() if the file is still referenced. Agent-Logs-Url: https://github.com/demaconsulting/FileAssert/sessions/ad3cb669-ac43-4111-be69-5b914dde7fc7 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
1 parent 8beb17f commit d51bc38

45 files changed

Lines changed: 1438 additions & 22 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cspell.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ words:
8080
- fileassert
8181
- FileAssert
8282
- filepart
83+
- selftest
8384
- testname
8485
- TMPL
8586
- triaging

.reviewmark.yaml

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,35 +23,84 @@ evidence-source:
2323
# Each review-set groups requirements, source, and tests for a coherent software unit
2424
# so that an AI-assisted review can verify consistency across the full evidence chain.
2525
reviews:
26+
# System review - end-to-end behavior and design overview
27+
- id: FileAssert-System
28+
title: Review of FileAssert System
29+
paths:
30+
- "docs/reqstream/fileassert-system.yaml"
31+
- "docs/design/introduction.md"
32+
- "docs/design/system.md"
33+
- "test/**/IntegrationTests.cs"
34+
35+
# Subsystem reviews - one per subsystem
36+
- id: FileAssert-Cli
37+
title: Review of FileAssert Cli Subsystem
38+
paths:
39+
- "docs/reqstream/subsystem-cli.yaml"
40+
- "docs/design/cli.md"
41+
- "test/**/CliSubsystemTests.cs"
42+
43+
- id: FileAssert-Configuration
44+
title: Review of FileAssert Configuration Subsystem
45+
paths:
46+
- "docs/reqstream/subsystem-configuration.yaml"
47+
- "docs/design/configuration.md"
48+
- "test/**/ConfigurationSubsystemTests.cs"
49+
50+
- id: FileAssert-Modeling
51+
title: Review of FileAssert Modeling Subsystem
52+
paths:
53+
- "docs/reqstream/subsystem-modeling.yaml"
54+
- "docs/design/modeling.md"
55+
- "test/**/ModelingSubsystemTests.cs"
56+
57+
- id: FileAssert-Utilities
58+
title: Review of FileAssert Utilities Subsystem
59+
paths:
60+
- "docs/reqstream/subsystem-utilities.yaml"
61+
- "docs/design/utilities.md"
62+
- "test/**/UtilitiesSubsystemTests.cs"
63+
64+
- id: FileAssert-SelfTest
65+
title: Review of FileAssert SelfTest Subsystem
66+
paths:
67+
- "docs/reqstream/subsystem-selftest.yaml"
68+
- "docs/design/selftest.md"
69+
- "test/**/SelfTestSubsystemTests.cs"
70+
2671
# Software unit reviews - one per class
2772
- id: FileAssert-Context
2873
title: Review of FileAssert Context Unit
2974
paths:
3075
- "docs/reqstream/unit-context.yaml"
76+
- "docs/design/context.md"
3177
- "src/**/Context.cs"
3278
- "test/**/ContextTests.cs"
79+
- "test/**/ContextNewPropertiesTests.cs"
3380

3481
- id: FileAssert-Program
3582
title: Review of FileAssert Program Unit
3683
paths:
3784
- "docs/reqstream/unit-program.yaml"
85+
- "docs/design/program.md"
3886
- "src/**/Program.cs"
3987
- "test/**/ProgramTests.cs"
40-
- "test/**/IntegrationTests.cs"
4188
- "test/**/Runner.cs"
4289
- "test/**/AssemblyInfo.cs"
4390

4491
- id: FileAssert-Validation
4592
title: Review of FileAssert Validation Unit
4693
paths:
4794
- "docs/reqstream/unit-validation.yaml"
95+
- "docs/design/validation.md"
4896
- "src/**/Validation.cs"
4997
- "test/**/ValidationTests.cs"
5098

5199
- id: FileAssert-PathHelpers
52100
title: Review of FileAssert PathHelpers Unit
53101
paths:
54102
- "docs/reqstream/unit-path-helpers.yaml"
103+
- "docs/design/path-helpers.md"
55104
- "src/**/PathHelpers.cs"
56105
- "test/**/PathHelpersTests.cs"
57106

@@ -61,7 +110,6 @@ reviews:
61110
- "docs/reqstream/unit-file-assert-rule.yaml"
62111
- "docs/design/file-assert-rule.md"
63112
- "src/**/FileAssertRule.cs"
64-
- "src/**/FileAssertData.cs"
65113
- "test/**/FileAssertRuleTests.cs"
66114

67115
- id: FileAssert-FileAssertFile
@@ -87,7 +135,12 @@ reviews:
87135
- "docs/design/file-assert-config.md"
88136
- "src/**/FileAssertConfig.cs"
89137
- "test/**/FileAssertConfigTests.cs"
90-
- "test/**/ContextNewPropertiesTests.cs"
138+
139+
- id: FileAssert-FileAssertData
140+
title: Review of FileAssert FileAssertData Unit
141+
paths:
142+
- "docs/design/file-assert-data.md"
143+
- "src/**/FileAssertData.cs"
91144

92145
# Platform and OTS dependency reviews
93146
- id: Platform-Support

docs/design/cli.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Cli Subsystem Design
2+
3+
## Overview
4+
5+
The Cli subsystem is responsible for translating the raw command-line argument array into a
6+
structured, immutable context object that the rest of the tool uses for output, configuration,
7+
and execution decisions.
8+
9+
## Subsystem Contents
10+
11+
| Unit | File | Responsibility |
12+
| :-------- | :------------ | :-------------------------------------------------------- |
13+
| `Context` | `Context.cs` | Parses arguments and owns all I/O operations. |
14+
15+
## Subsystem Responsibilities
16+
17+
- Parse all supported flags (`--version`, `--help`, `--silent`, `--validate`, `--log`,
18+
`--results`, `--config`) and positional filter arguments.
19+
- Reject unknown or malformed arguments with a descriptive `ArgumentException`.
20+
- Open and manage a log file when `--log` is specified.
21+
- Write output to stdout and the log file; write errors to stderr and the log file.
22+
- Expose an exit code that reflects whether any errors have been reported.
23+
24+
## Interactions with Other Subsystems
25+
26+
| Consumer | Usage |
27+
| :---------------- | :------------------------------------------------------------------- |
28+
| Program | Creates a `Context` and passes it to all downstream operations. |
29+
| Configuration | Receives a `Context` to report errors and write progress output. |
30+
| Modeling | Receives a `Context` to write error messages for assertion failures. |
31+
| SelfTest | Receives a `Context` to write validation results and errors. |
32+
33+
## Design Decisions
34+
35+
- **Immutable context object**: Properties are set once via `private init` accessors, preventing
36+
accidental mutation after the context is created.
37+
- **Internal ArgumentParser helper**: Argument parsing is encapsulated in a private nested
38+
class, keeping the public `Context` interface focused on output and state rather than parsing.
39+
- **AutoFlush log writer**: The log file stream is opened with `AutoFlush = true` so that log
40+
entries are written to disk immediately, even if the process terminates unexpectedly.

docs/design/configuration.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Configuration Subsystem Design
2+
3+
## Overview
4+
5+
The Configuration subsystem is responsible for reading the YAML test-suite configuration file
6+
and constructing the domain object hierarchy that drives test execution. It owns the data
7+
transfer objects used during deserialization and the top-level configuration class that loads
8+
and runs the tests.
9+
10+
## Subsystem Contents
11+
12+
| Unit | File | Responsibility |
13+
| :----------------- | :--------------------- | :---------------------------------------------------------- |
14+
| `FileAssertConfig` | `FileAssertConfig.cs` | Loads the YAML file and runs the filtered test suite. |
15+
| `FileAssertData` | `FileAssertData.cs` | Data transfer objects for YAML deserialization. |
16+
17+
## Subsystem Responsibilities
18+
19+
- Read and deserialize a YAML configuration file using YamlDotNet.
20+
- Tolerate unknown YAML properties for forward compatibility.
21+
- Construct the full `FileAssertTest → FileAssertFile → FileAssertRule` hierarchy from the
22+
deserialized data.
23+
- Resolve the base directory for glob patterns from the configuration file path.
24+
- Filter tests by name or tag before execution.
25+
26+
## Interactions with Other Subsystems
27+
28+
| Dependency | Usage |
29+
| :---------- | :-------------------------------------------------------------------------- |
30+
| Cli | Receives a `Context` to report errors and write progress output. |
31+
| Modeling | Delegates test construction to `FileAssertTest.Create` and execution to |
32+
| | `FileAssertTest.Run`. |
33+
34+
## YAML Configuration Format
35+
36+
The top-level YAML structure is:
37+
38+
```yaml
39+
tests:
40+
- name: "Test Name"
41+
tags:
42+
- tag1
43+
files:
44+
- pattern: "**/*.cs"
45+
min: 1
46+
rules:
47+
- contains: "Copyright"
48+
```
49+
50+
## Design Decisions
51+
52+
- **Separation of data and domain objects**: The `FileAssertData` classes are pure data holders
53+
with no logic. The Modeling subsystem owns the domain objects built from them.
54+
- **Forward-compatible deserialization**: `IgnoreUnmatchedProperties()` allows configuration
55+
files to contain keys introduced in later tool versions without causing parse failures.
56+
- **Base directory from config path**: Resolving glob patterns relative to the configuration
57+
file location is more intuitive than the working directory, especially when the tool is
58+
invoked from a build script in a different directory.

docs/design/context.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Context Design
2+
3+
## Overview
4+
5+
`Context` is the command-line argument parser and I/O owner for FileAssert. It translates the
6+
raw `string[]` argument array into named properties, manages the optional log file stream, and
7+
provides a unified interface for writing output and errors throughout the tool's execution.
8+
9+
## Class Structure
10+
11+
### Properties
12+
13+
| Property | Type | Description |
14+
| :--------------------- | :---------------------- | :------------------------------------------------------------ |
15+
| `Version` | `bool` | Set when `--version` or `-v` is present. |
16+
| `Help` | `bool` | Set when `--help`, `-h`, or `-?` is present. |
17+
| `Silent` | `bool` | Set when `--silent` is present. |
18+
| `Validate` | `bool` | Set when `--validate` is present. |
19+
| `ResultsFile` | `string?` | Path provided via `--results`, or null. |
20+
| `ConfigFile` | `string` | Path provided via `--config`; defaults to `.fileassert.yaml`. |
21+
| `IsConfigFileExplicit` | `bool` | True when `--config` was explicitly specified. |
22+
| `Filters` | `IReadOnlyList<string>` | Positional arguments treated as test name or tag filters. |
23+
| `ExitCode` | `int` | Returns `1` if any errors have been reported; otherwise `0`. |
24+
25+
### Factory Method
26+
27+
```csharp
28+
public static Context Create(string[] args)
29+
```
30+
31+
Delegates argument parsing to the private `ArgumentParser` nested class. Opens a log file if
32+
`--log` was specified. Returns the fully initialized `Context` instance.
33+
34+
### Output Methods
35+
36+
```csharp
37+
public void WriteLine(string message)
38+
public void WriteError(string message)
39+
```
40+
41+
`WriteLine` writes to stdout and the log file (unless `--silent` suppresses console output).
42+
`WriteError` sets the internal error flag, writes to stderr in red (unless silent), and writes
43+
to the log file.
44+
45+
### Argument Parsing
46+
47+
The private nested class `ArgumentParser` processes each argument in order:
48+
49+
- Flag arguments (starting with `--` or `-`) are matched by a `switch` statement.
50+
- Arguments requiring a value (`--log`, `--results`, `--config`) consume the next element
51+
from the argument array and throw `ArgumentException` if no value follows.
52+
- Unknown flag arguments (starting with `-`) throw `ArgumentException`.
53+
- All other arguments are accumulated in the `Filters` list.
54+
55+
## Design Decisions
56+
57+
- **Sealed with IDisposable**: The class is sealed to prevent inheritance of internal state, and
58+
implements `IDisposable` to ensure the log file stream is always closed.
59+
- **Factory method**: The `Create` factory method is `public` so tests and the self-validation
60+
tests can construct a context directly without invoking `Main`.
61+
- **Error flag over exception**: `WriteError` sets a flag rather than throwing, so the tool
62+
completes all assertions before reporting a final failure via the exit code.

docs/design/definition.yaml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,21 @@ resource-path:
55
input-files:
66
- docs/design/title.txt
77
- docs/design/introduction.md
8-
- docs/design/file-assert-rule.md
9-
- docs/design/file-assert-file.md
10-
- docs/design/file-assert-test.md
8+
- docs/design/system.md
9+
- docs/design/program.md
10+
- docs/design/cli.md
11+
- docs/design/context.md
12+
- docs/design/configuration.md
1113
- docs/design/file-assert-config.md
14+
- docs/design/file-assert-data.md
15+
- docs/design/modeling.md
16+
- docs/design/file-assert-test.md
17+
- docs/design/file-assert-file.md
18+
- docs/design/file-assert-rule.md
19+
- docs/design/utilities.md
20+
- docs/design/path-helpers.md
21+
- docs/design/selftest.md
22+
- docs/design/validation.md
1223
template: template.html
1324
table-of-contents: true
1425
number-sections: true

docs/design/file-assert-data.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# FileAssertData Design
2+
3+
## Overview
4+
5+
`FileAssertData` is the set of YAML data transfer objects (DTOs) used by YamlDotNet to
6+
deserialize the FileAssert configuration file. Each class maps directly to a YAML structure
7+
and is intentionally free of business logic. Domain objects are constructed from these DTOs
8+
by the Modeling subsystem.
9+
10+
## Class Structure
11+
12+
### FileAssertRuleData
13+
14+
Represents a single content validation rule within a file assertion.
15+
16+
| Property | YAML alias | Type | Description |
17+
| :--------- | :---------- | :-------- | :---------------------------------------------- |
18+
| `Contains` | `contains` | `string?` | Substring that file content must contain. |
19+
| `Matches` | `matches` | `string?` | Regular expression the file content must match. |
20+
21+
Exactly one property shall be set per rule. The `FileAssertRule.Create` factory enforces this.
22+
23+
### FileAssertFileData
24+
25+
Represents a file pattern assertion within a test.
26+
27+
| Property | YAML alias | Type | Description |
28+
| :-------- | :--------- | :--------------------------- | :----------------------------------------------------------- |
29+
| `Pattern` | `pattern` | `string?` | Glob pattern used to locate files. |
30+
| `Min` | `min` | `int?` | Minimum number of matching files; null means no lower bound. |
31+
| `Max` | `max` | `int?` | Maximum number of matching files; null means no upper bound. |
32+
| `Rules` | `rules` | `List<FileAssertRuleData>?` | Content rules applied to each matched file. |
33+
34+
### FileAssertTestData
35+
36+
Represents a named test within the configuration.
37+
38+
| Property | YAML alias | Type | Description |
39+
| :------- | :--------- | :--------------------------- | :-------------------------------------------- |
40+
| `Name` | `name` | `string?` | Human-readable name for the test. |
41+
| `Tags` | `tags` | `List<string>?` | Tags used for command-line filter selection. |
42+
| `Files` | `files` | `List<FileAssertFileData>?` | File assertions belonging to this test. |
43+
44+
### FileAssertConfigData
45+
46+
Represents the top-level configuration document.
47+
48+
| Property | YAML alias | Type | Description |
49+
| :------- | :--------- | :--------------------------- | :-------------------------------------------- |
50+
| `Tests` | `tests` | `List<FileAssertTestData>?` | Tests defined in this configuration file. |
51+
52+
## Design Decisions
53+
54+
- **Nullable reference type properties**: All properties are nullable to correctly represent
55+
absent YAML keys without throwing during deserialization.
56+
- **No validation logic in DTOs**: Validation and construction of domain objects is the
57+
responsibility of the factory methods in the Modeling subsystem, keeping DTOs simple.
58+
- **YamlMember aliases**: Explicit `[YamlMember(Alias = "...")]` attributes tie each property
59+
to its YAML key, decoupling C# naming conventions from the YAML schema.

0 commit comments

Comments
 (0)