docs: map existing codebase
- STACK.md - Technologies and dependencies (.NET 4.7.2, NuGet, Costura.Fody) - ARCHITECTURE.md - Layered CLI with ICncMachine factory pattern - STRUCTURE.md - Directory layout and where to add new code - CONVENTIONS.md - C# style, naming, result wrapper pattern - TESTING.md - NUnit 3 + Moq, stubs, ignored FOCAS tests - INTEGRATIONS.md - FOCAS, LSV2, FTP, RSA licensing - CONCERNS.md - Blocking async, silent catch, no logging, Windows-only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f55d0b313b
commit
dabcf989d9
7 changed files with 913 additions and 0 deletions
156
.paul/codebase/ARCHITECTURE.md
Normal file
156
.paul/codebase/ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# Architecture
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## Pattern Overview
|
||||
|
||||
**Overall:** Layered CLI console application with abstract machine interface, factory dispatch, and offline license gate.
|
||||
|
||||
**Key Characteristics:**
|
||||
- Single Windows EXE (all dependencies embedded via Costura.Fody)
|
||||
- Polymorphic multi-vendor CNC support via `ICncMachine` interface
|
||||
- Factory pattern for manufacturer selection at runtime
|
||||
- Async/await throughout (Task-based), but blocked at CLI boundary via `.GetAwaiter().GetResult()`
|
||||
- Result-wrapper pattern (`CncResult<T>`) instead of exceptions for CNC operations
|
||||
- RSA license validation gate on every startup
|
||||
|
||||
## Layers
|
||||
|
||||
**CLI Entry Layer:**
|
||||
- Purpose: Parse args, validate license, dispatch to action (Scarica/Invia)
|
||||
- Contains: `Program.cs` (main orchestration), `ArgParser.cs` (regex arg parsing), `InputArgs.cs` (config object)
|
||||
- Depends on: Licensing layer, CNC abstraction layer
|
||||
- Error output: Negative exit codes (-100 to -208) mapped to Italian user messages
|
||||
|
||||
**Licensing Layer:**
|
||||
- Purpose: Prevent execution on unlicensed machines
|
||||
- Contains: `Licensing/LicenseValidator.cs`, `Licensing/MachineFingerprint.cs`, `Licensing/LicenseFile.cs`
|
||||
- Depends on: WMI (System.Management), RSA crypto
|
||||
- Used by: CLI entry layer (startup check only)
|
||||
|
||||
**CNC Abstraction Layer:**
|
||||
- Purpose: Uniform interface over 4 different CNC protocols
|
||||
- Contains: `Cnc/ICncMachine.cs`, `Cnc/IFanucMachine.cs`, `Cnc/CncMachineFactory.cs`, `Cnc/Models/`
|
||||
- Key types: `CncResult<T>`, `CncError`, `CncManufacturer`, `ConnectionState`, `CncProgram`
|
||||
- Used by: CLI entry layer
|
||||
|
||||
**Manufacturer Implementations:**
|
||||
- Purpose: Protocol-specific CNC communication
|
||||
- Contains: `Cnc/Fanuc/`, `Cnc/Heidenhain/`, `Cnc/Siemens/`, `Cnc/Mitsubishi/`
|
||||
- Each implements `ICncMachine` (Fanuc also implements `IFanucMachine`)
|
||||
- Depends on: Protocol libraries (FOCAS DLL, TCP socket, FtpWebRequest)
|
||||
|
||||
**Validation Layer:**
|
||||
- Purpose: Pre-upload NC program syntax checking
|
||||
- Contains: `Cnc/INcProgramValidator.cs`, `Cnc/NcProgramValidator.cs`
|
||||
- Injected into machine implementations; upload blocked on Error severity
|
||||
- Depends on: Nothing external
|
||||
|
||||
**NC Program Parsing:**
|
||||
- Purpose: Parse/format Fanuc composite NC file format
|
||||
- Contains: `FanucProgram.cs` (program + tooloffset + workzero sections)
|
||||
- Used by: CLI entry layer post-download
|
||||
|
||||
## Data Flow
|
||||
|
||||
**Scarica (Download from CNC):**
|
||||
```
|
||||
CLI args
|
||||
→ ArgParser.Parse() → InputArgs
|
||||
→ LicenseValidator.Validate() [exit -1xx on failure]
|
||||
→ CncMachineFactory.Create(InputArgs) → ICncMachine
|
||||
→ machine.ConnectAsync() → CncResult<bool>
|
||||
→ machine.ReadProgramAsync(path) → CncResult<string>
|
||||
→ [IFanucMachine cast] ReadToolDataAsync / ReadWorkZeroDataAsync
|
||||
→ FanucProgram.Format() → composite file string
|
||||
→ File.WriteAllText(localPath)
|
||||
```
|
||||
|
||||
**Invia (Upload to CNC):**
|
||||
```
|
||||
CLI args
|
||||
→ ArgParser.Parse() → InputArgs
|
||||
→ LicenseValidator.Validate() [exit -1xx on failure]
|
||||
→ CncMachineFactory.Create(InputArgs) → ICncMachine
|
||||
→ File.ReadAllText(localPath)
|
||||
→ NcProgramValidator.Validate() [exit on Error severity]
|
||||
→ machine.ConnectAsync()
|
||||
→ machine.WriteProgramAsync(path, content) → CncResult<bool>
|
||||
```
|
||||
|
||||
**State Management:**
|
||||
- No persistent in-memory state between invocations (each run is independent)
|
||||
- Machine state tracked per-instance: `ConnectionState` enum + `StateChanged` event
|
||||
- Thread safety: `SemaphoreSlim` gate per machine instance
|
||||
|
||||
## Key Abstractions
|
||||
|
||||
**ICncMachine:**
|
||||
- Purpose: Uniform contract for all CNC machines
|
||||
- Location: `Cnc/ICncMachine.cs`
|
||||
- Methods: `ConnectAsync`, `DisconnectAsync`, `ReadProgramAsync`, `WriteProgramAsync`, `ReadAsync`, `DeleteProgramAsync`, `ReadActiveProgramAsync`, `SelectMainProgramAsync`
|
||||
- Pattern: Interface + factory dispatch
|
||||
|
||||
**IFanucMachine:**
|
||||
- Purpose: Fanuc-specific extensions (tool offsets, work zero)
|
||||
- Location: `Cnc/IFanucMachine.cs`
|
||||
- Extends: `ICncMachine`
|
||||
- Pattern: Interface specialization
|
||||
|
||||
**CncResult<T>:**
|
||||
- Purpose: Typed result wrapper replaces exception-based control flow
|
||||
- Location: `Cnc/Models/CncResult.cs`
|
||||
- Factories: `Ok()`, `Fail()`, `Cancelled()`, `OkWithWarnings()`
|
||||
- Properties: `Success`, `Errors`, `WasCancelled`, `Value`
|
||||
|
||||
**IFocasDialect:**
|
||||
- Purpose: Abstract FOCAS version differences (Legacy vs Modern API)
|
||||
- Location: `Cnc/Fanuc/IFocasDialect.cs`
|
||||
- Implementations: `LegacyFocasDialect.cs`, `ModernFocasDialect.cs`
|
||||
- Detection: `FanucDialectDetector.cs` at connect time
|
||||
|
||||
**CncMachineFactory:**
|
||||
- Purpose: Create correct ICncMachine from InputArgs
|
||||
- Location: `Cnc/CncMachineFactory.cs`
|
||||
- Dispatches on: `CncManufacturer` enum (Fanuc, Heidenhain, Siemens, Mitsubishi)
|
||||
|
||||
## Entry Points
|
||||
|
||||
**CLI Entry:**
|
||||
- Location: `Program.cs` (Main method)
|
||||
- Triggers: Process execution from command line or calling application
|
||||
- Responsibilities: Arg parsing → license check → machine factory → action dispatch → exit code
|
||||
|
||||
**Argument Parser:**
|
||||
- Location: `ArgParser.cs` (static `Parse(string[])`)
|
||||
- Returns: `InputArgs` with all 16 CLI parameters normalized
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Strategy:** Result wrapper at CNC layer, exit codes at CLI boundary, ArgumentNullException for null guards
|
||||
|
||||
**Patterns:**
|
||||
- `CncResult<T>.Fail(errors)` for CNC operation failures
|
||||
- `ArgumentNullException` for constructor null guards (`Cnc/Fanuc/FanucMachine.cs`)
|
||||
- Exit codes -100 to -208 in `Program.cs` for user-facing errors
|
||||
- `try/finally` with `connected` flag for connection leak prevention (`Program.cs`)
|
||||
- `catch { }` (silent) on disconnect cleanup paths — known weakness (see CONCERNS.md)
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
**Logging:**
|
||||
- `Console.WriteLine` only — no structured logging framework
|
||||
- Debug mode (`-debug=` arg): keeps terminal open after operation
|
||||
|
||||
**Validation:**
|
||||
- `NcProgramValidator` injected into machine constructors
|
||||
- Runs before upload; blocked on `ValidationSeverity.Error`
|
||||
|
||||
**Cancellation:**
|
||||
- `CancellationToken` passed through all async methods
|
||||
- CLI does not currently expose cancellation to user
|
||||
|
||||
---
|
||||
|
||||
*Architecture analysis: 2026-05-18*
|
||||
*Update when major patterns change*
|
||||
152
.paul/codebase/CONCERNS.md
Normal file
152
.paul/codebase/CONCERNS.md
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## Tech Debt
|
||||
|
||||
**Blocking async calls at CLI boundary:**
|
||||
- Issue: 56+ `.GetAwaiter().GetResult()` calls block async operations synchronously
|
||||
- Files: `Program.cs` (lines 90, 101, 122, 142, 166, 200, 221, 240, 262), machine classes
|
||||
- Why: Main() was not async when initially written; .NET 4.7.2 supports async Main via C# 7.1
|
||||
- Impact: Thread pool starvation risk, deadlock risk in certain SynchronizationContext scenarios, harder debugging
|
||||
- Fix: Refactor `Program.Main` to `static async Task<int> Main(string[] args)`, propagate `await` throughout
|
||||
|
||||
**Silent exception handlers (catch without logging):**
|
||||
- Issue: `try { ... } catch { }` swallows exceptions with no trace
|
||||
- Files: `Cnc/Fanuc/FanucMachine.cs` (disconnect cleanup), `Cnc/Siemens/SiemensMachine.cs`, `Cnc/Heidenhain/HeidenhainMachine.cs`, `Cnc/Heidenhain/Lsv2Client.cs`
|
||||
- Why: Cleanup paths (disconnect, logout) should not propagate to caller; silence was intentional
|
||||
- Impact: Resource leaks masked, production issues undiagnosable, disconnect failures invisible
|
||||
- Fix: Log at minimum to debug/trace: `catch (Exception ex) { /* log ex */ }`. Add logging framework.
|
||||
|
||||
**No structured logging framework:**
|
||||
- Issue: Entire codebase uses `Console.WriteLine` (98+ calls in `Program.cs` alone)
|
||||
- Files: `Program.cs`, all machine implementations
|
||||
- Why: MVP simplicity; tool was always a CLI
|
||||
- Impact: No log levels, no timestamps, no file logging, production issues undiagnosable
|
||||
- Fix: Add Serilog or NLog. Replace Console.WriteLine with `_logger.Information()`. Add request/response tracing to FOCAS calls.
|
||||
|
||||
**Large monolithic FanucMachine:**
|
||||
- Issue: `Cnc/Fanuc/FanucMachine.cs` is ~740 lines with complex state management
|
||||
- Files: `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Why: FOCAS protocol has many edge cases; chunked transfer and offset handling grew organically
|
||||
- Impact: Hard to test individual branches; buffer handling edge cases unclear
|
||||
- Fix: Extract `IFocasTransferHandler` for chunk upload/download logic; separate offset data reader
|
||||
|
||||
**`string.Format()` over `$""` interpolation:**
|
||||
- Issue: Old string formatting style throughout validator and some machine code
|
||||
- Files: `Cnc/NcProgramValidator.cs`, `Program.cs`
|
||||
- Why: Legacy code predates C# 6 adoption on this project
|
||||
- Impact: Cosmetic; harder to read format strings
|
||||
- Fix: Opportunistic migration to `$""` during edits
|
||||
|
||||
## Known Issues / Incomplete Implementations
|
||||
|
||||
**Heidenhain ReadActiveProgramAsync / SelectMainProgram not implemented:**
|
||||
- Symptoms: Returns `CncResult.Fail("Not supported via basic LSV2")`
|
||||
- Files: `Cnc/Heidenhain/HeidenhainMachine.cs`
|
||||
- Root cause: LSV2 protocol complexity; feature not required for initial release
|
||||
- Workaround: Users specify program path explicitly
|
||||
|
||||
**Siemens ReadActiveProgramAsync / SelectMainProgram not implemented:**
|
||||
- Symptoms: Returns stub failure
|
||||
- Files: `Cnc/Siemens/SiemensMachine.cs`
|
||||
- Root cause: FTP protocol doesn't expose active program info
|
||||
- Workaround: Users specify program path explicitly
|
||||
|
||||
**MachineSnapshot returns stub data for Heidenhain/Siemens/Mitsubishi:**
|
||||
- Files: `Cnc/Heidenhain/HeidenhainMachine.cs`, `Cnc/Siemens/SiemensMachine.cs`, `Cnc/Mitsubishi/MitsubishiMachine.cs`
|
||||
- Issue: All snapshot fields return Unknown/empty; no real machine state read
|
||||
- Impact: No diagnostic info available for non-Fanuc machines
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**RSA public key hardcoded in binary:**
|
||||
- Risk: Key embedded as const string in binary; cannot be rotated without recompile and redeploy
|
||||
- Files: `Licensing/LicenseValidator.cs`
|
||||
- Current mitigation: Asymmetric RSA — private key is vendor-only; hardcoded public key is acceptable for this use case
|
||||
- Recommendation: Document key rotation procedure; consider adding license version/expiration metadata for future revocation
|
||||
|
||||
**MachineFingerprint null dereference on unusual hardware:**
|
||||
- Risk: `mo.Properties["processorID"].Value.ToString()` throws NullReferenceException if WMI property missing
|
||||
- Files: `Licensing/MachineFingerprint.cs`
|
||||
- Current mitigation: None
|
||||
- Fix: `mo.Properties["processorID"]?.Value?.ToString() ?? "unknown"`
|
||||
|
||||
**Obsolete crypto APIs:**
|
||||
- Risk: `RSACryptoServiceProvider` and `SHA256CryptoServiceProvider` are obsolete in .NET 6+
|
||||
- Files: `Licensing/LicenseValidator.cs`
|
||||
- Current mitigation: .NET 4.7.2 target — obsolete warning only, not broken
|
||||
- Fix when upgrading: Use `RSA.Create()` + `VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)`
|
||||
|
||||
**SHA256 provider not explicitly disposed:**
|
||||
- Risk: Minor resource leak in license validation path
|
||||
- Files: `Licensing/LicenseValidator.cs`
|
||||
- Fix: Wrap in `using (var sha = new SHA256CryptoServiceProvider()) { ... }`
|
||||
|
||||
## Platform Constraints
|
||||
|
||||
**Windows-only (hard constraint):**
|
||||
- FOCAS1 DLL (`Fwlib32.dll`) is 32-bit Windows native — no Linux/macOS support
|
||||
- WMI (`System.Management`) Windows-only — licensing system non-functional on Linux
|
||||
- Files: `Cnc/Fanuc/libs/`, `Licensing/MachineFingerprint.cs`, `fwlib32.cs`
|
||||
- Impact: Cannot run on Linux/macOS; CI on Linux can only test non-FOCAS paths
|
||||
- Action if cross-platform needed: Abstract fingerprinting behind `IMachineFingerprint`; already done — add Linux implementation using `/proc/cpuinfo` or `dmidecode`
|
||||
|
||||
**FOCAS DLL version sensitivity:**
|
||||
- Risk: FOCAS API changes between Fanuc control versions; `FanucDialectDetector` auto-detects but may fail on unknown versions
|
||||
- Files: `Cnc/Fanuc/FanucDialectDetector.cs`, `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Mitigation: Dialect abstraction layer (`IFocasDialect`) isolates version differences
|
||||
|
||||
## Performance Bottlenecks
|
||||
|
||||
**In-memory accumulation for large NC programs:**
|
||||
- Issue: `UploadProgramByIdentifier` appends to `StringBuilder` for entire program before writing
|
||||
- Files: `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Impact: For programs >10MB, high memory allocation; streaming to file would be more efficient
|
||||
- Fix: Write chunks directly to `FileStream` instead of accumulating in memory
|
||||
|
||||
**Polling with 100ms busy-wait during transfer:**
|
||||
- Issue: `ct.WaitHandle.WaitOne(100)` loops during buffer waits
|
||||
- Files: `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Impact: Wastes thread-pool slot; CPU cycles during transfer
|
||||
- Fix: Use `await Task.Delay(100, ct)` instead of blocking WaitOne
|
||||
|
||||
**Network connection timeout via `.Wait()` with boolean return:**
|
||||
- Issue: `_tcp.ConnectAsync().Wait(timeout)` — if task never completes, does not abort it
|
||||
- Files: `Cnc/Heidenhain/Lsv2Client.cs`
|
||||
- Fix: `await Task.WhenAny(connectTask, Task.Delay(timeout, ct))` + cancellation
|
||||
|
||||
## Fragile Areas
|
||||
|
||||
**FOCAS dialect detection (`FanucDialectDetector`):**
|
||||
- Files: `Cnc/Fanuc/FanucDialectDetector.cs`
|
||||
- Why fragile: Relies on probing specific FOCAS API calls to detect version; untested against full range of Fanuc control generations
|
||||
- Safe modification: Always test against physical hardware after changes; log detected dialect version
|
||||
|
||||
**License validation (no recovery path):**
|
||||
- Files: `Licensing/LicenseValidator.cs`, `Licensing/MachineFingerprint.cs`
|
||||
- Why fragile: Any WMI failure or file read error produces a hard exit with no diagnostic for user
|
||||
- Safe modification: Add exception handling with user-facing error message; distinguish "no license file" from "invalid license" from "fingerprint failure"
|
||||
|
||||
**Integration tests with hardcoded IPs:**
|
||||
- Files: `NcProgramManager.Tests/Integration/SiemensMachineIntegrationTests.cs`, `HeidenhainMachineIntegrationTests.cs`, `MitsubishiMachineIntegrationTests.cs`
|
||||
- Why fragile: Tests will fail in CI without physical hardware at specific IPs
|
||||
- Fix: Make IPs configurable via environment variables; skip integration tests in CI by default
|
||||
|
||||
## Missing / Not Covered
|
||||
|
||||
- No CLI-level tests (no test for `Program.cs` orchestration or exit code behavior)
|
||||
- No tests for `MachineFingerprint` (WMI, no mock tests)
|
||||
- No tests for `LicenseFile` parsing edge cases (corrupt Base64, empty file)
|
||||
- No structured logging or diagnostics framework
|
||||
- No error code documentation in code (only in `README.md`)
|
||||
- No architecture documentation (FOCAS dialect selection logic undocumented in code)
|
||||
|
||||
---
|
||||
|
||||
**Overall Assessment:** Architecture is solid — clean machine abstraction, well-structured interfaces, good error propagation via `CncResult<T>`. Main concerns are operational (logging, blocking async, empty catch blocks) rather than structural. Platform constraints (Windows, FOCAS DLL) are intentional for the target environment.
|
||||
|
||||
---
|
||||
|
||||
*Concerns analysis: 2026-05-18*
|
||||
*Update as issues are resolved or discovered*
|
||||
122
.paul/codebase/CONVENTIONS.md
Normal file
122
.paul/codebase/CONVENTIONS.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Files:**
|
||||
- PascalCase for all `.cs` files: `FanucMachine.cs`, `CncResult.cs`
|
||||
- Interfaces: I-prefix PascalCase: `ICncMachine.cs`, `IFocasDialect.cs`
|
||||
- Tests: `{Subject}Tests.cs` or `{Subject}IntegrationTests.cs`
|
||||
- Config classes: `{Manufacturer}ConnectionConfig.cs`
|
||||
|
||||
**Classes:**
|
||||
- PascalCase for all classes
|
||||
- Sealed preferred for implementations (not open to inheritance)
|
||||
- Examples: `NcProgramValidator.cs`, `CncResult.cs`
|
||||
- Manufacturer-prefixed where relevant: `FanucMachine`, `HeidenhainMachine`, `SiemensMachine`
|
||||
|
||||
**Interfaces:**
|
||||
- I-prefix strictly followed: `ICncMachine`, `IFanucMachine`, `ILicenseValidator`, `IFocasDialect`
|
||||
|
||||
**Fields:**
|
||||
- Private: `_camelCase` with underscore prefix
|
||||
- Example: `_config`, `_validator`, `_state`, `_hndl` in `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Constants (public): PascalCase — `AlarmSlots`, `TransferChunkSize` in `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Constants (private): can be UPPER_CASE or PascalCase
|
||||
- Static readonly: `_camelCase` with underscore
|
||||
|
||||
**Properties:**
|
||||
- PascalCase, read-only preferred
|
||||
- Example: `Name`, `Comment`, `Content`, `Path` in `Cnc/Models/CncProgram.cs`
|
||||
|
||||
**Methods:**
|
||||
- PascalCase for all public methods: `ConnectAsync()`, `ReadProgramAsync()`
|
||||
- `Async` suffix on all methods returning `Task<T>` or `Task`
|
||||
- Private helpers: `PascalCase` (same as public, no underscore)
|
||||
- Example: `NcProgramValidator.cs`
|
||||
|
||||
**Enums:**
|
||||
- PascalCase for type name, PascalCase for values
|
||||
- Examples: `CncManufacturer.Fanuc`, `ConnectionState.Connected`, `FanucTransport.Ethernet`
|
||||
|
||||
## Code Style
|
||||
|
||||
**Formatting:**
|
||||
- 4-space indentation
|
||||
- Allman brace style (opening brace on new line for classes and methods)
|
||||
- Example: `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Single-line property getters: inline `{ get { return _x; } }`
|
||||
- No `.editorconfig` or StyleCop — conventions enforced by practice
|
||||
|
||||
**String Formatting:**
|
||||
- `string.Format()` for parameterized messages (not `$""` interpolation)
|
||||
- Example: `Cnc/NcProgramValidator.cs` lines with format strings
|
||||
- `+` concatenation for console output in `Program.cs`
|
||||
|
||||
**Async:**
|
||||
- `default` parameter for `CancellationToken` on async methods
|
||||
- `ConfigureAwait(false)` on library-level code
|
||||
- `Task.Run()` for blocking FOCAS calls in async context (RunGuardedAsync pattern)
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Order:**
|
||||
1. System namespaces
|
||||
2. External packages
|
||||
3. Internal project namespaces
|
||||
|
||||
No path aliases (not applicable to .NET Framework / no source generators).
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Patterns:**
|
||||
- Null guards at constructor: `if (config == null) throw new ArgumentNullException("config")`
|
||||
- Example: `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Null-coalescing for optional deps: `_validator = validator ?? new NcProgramValidator(...)`
|
||||
- `CncResult<T>` wrapper for all CNC operations (not exceptions)
|
||||
- Exit codes at CLI boundary: -100 to -208 in `Program.cs`
|
||||
- `try/finally` with `connected` flag for connection cleanup in `Program.cs`
|
||||
|
||||
**Result Wrapper Factories:**
|
||||
- `CncResult<T>.Ok(value)` — success
|
||||
- `CncResult<T>.Fail(errors)` — failure with error list
|
||||
- `CncResult<T>.Cancelled()` — cancellation
|
||||
- `CncResult<T>.OkWithWarnings(value, errors)` — partial success
|
||||
|
||||
## Logging
|
||||
|
||||
**Framework:** None — `Console.WriteLine` only
|
||||
|
||||
**Patterns:**
|
||||
- User-facing output: `Console.WriteLine()` in `Program.cs`
|
||||
- Error output: same Console (no stderr separation)
|
||||
- No log levels, no timestamps, no structured logging
|
||||
- Debug mode via `-debug=` arg keeps terminal open post-operation
|
||||
|
||||
## Comments
|
||||
|
||||
**When to Comment:**
|
||||
- Document intent/constraints, not obvious code
|
||||
- Example: `NcProgramValidator.cs` — "Name-format check (uses just the bare filename without path)"
|
||||
- Separator line style for section breaks: `// ── private helpers ─────────────────`
|
||||
- Example: `NcProgramValidator.cs`
|
||||
|
||||
**XML Doc Comments:**
|
||||
- Sparse; only on public classes and key methods
|
||||
- Format: `/// <summary>Brief description.</summary>`
|
||||
- Examples: `NcProgramValidator.cs`, `CncResult.cs`, `ValidationResult.cs`
|
||||
|
||||
**No TODO/FIXME comments found in codebase** — known deferred work tracked in STATE.md.
|
||||
|
||||
## Function Design
|
||||
|
||||
- Private async methods wrap blocking/mixed code with semaphore locking (RunGuardedAsync pattern)
|
||||
- Example: `Cnc/Fanuc/FanucMachine.cs` RunGuardedAsync
|
||||
- Large transfer methods split into chunked helpers (`TransferChunked`, `UploadProgramByIdentifier`)
|
||||
- Interface/implementation pairs for all protocol clients (I-prefix interface + concrete)
|
||||
|
||||
---
|
||||
|
||||
*Conventions analysis: 2026-05-18*
|
||||
*Update when style decisions change*
|
||||
87
.paul/codebase/INTEGRATIONS.md
Normal file
87
.paul/codebase/INTEGRATIONS.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# External Integrations
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## CNC Machine Protocols
|
||||
|
||||
**Fanuc FOCAS1/FOCAS2 (proprietary):**
|
||||
- Used for: Program upload/download, tool data, work zero offset, machine state
|
||||
- SDK/Client: `fwlib32.cs` (11,569 lines, P/Invoke wrapper, Fanuc copyright 2002-2014)
|
||||
- Native DLLs: `Cnc/Fanuc/libs/Fwlib32.dll`, `fwlibe1.dll`, `fwlibNCG.dll`
|
||||
- Transport: Ethernet TCP (port 8193 default) or HSSB (legacy serial bus)
|
||||
- Main implementation: `Cnc/Fanuc/FanucMachine.cs`
|
||||
- Dialect abstraction: `Cnc/Fanuc/IFocasDialect.cs` → `LegacyFocasDialect.cs` / `ModernFocasDialect.cs`
|
||||
- Auto-detection: `Cnc/Fanuc/FanucDialectDetector.cs` (detects FOCAS version at connect time)
|
||||
- Config: `Cnc/Fanuc/FanucConnectionConfig.cs` (IP, port, HSSB node, transport type)
|
||||
- Platform: Windows only (DLL is 32-bit native)
|
||||
|
||||
**Heidenhain LSV2 (proprietary TCP protocol):**
|
||||
- Used for: Program transfer to/from Heidenhain iTNC/TNC controllers
|
||||
- Client: Custom TCP implementation `Cnc/Heidenhain/Lsv2Client.cs`
|
||||
- Default port: 19000
|
||||
- Auth: Username + password required
|
||||
- Framing: STX, SIZE, CMD, data, CRC-16/CCITT
|
||||
- Commands implemented: T_LS_SELECT, T_LS_LOG_IN, T_LS_LOG_OUT, T_R_FL (read file), T_S_FL (send file), T_FD
|
||||
- Main implementation: `Cnc/Heidenhain/HeidenhainMachine.cs`
|
||||
- Config: `Cnc/Heidenhain/HeidenhainConnectionConfig.cs`
|
||||
- Note: ReadActiveProgramAsync / SelectMainProgram not implemented (LSV2 limitation)
|
||||
|
||||
**Siemens Sinumerik FTP:**
|
||||
- Used for: Program transfer to/from Siemens Sinumerik controllers
|
||||
- Protocol: Standard FTP (RFC 959) via `System.Net.FtpWebRequest`
|
||||
- Default port: 21
|
||||
- Default program dir: `/_N_MPF_DIR/`
|
||||
- Auth: Username + password
|
||||
- Client: `Cnc/Siemens/SiemensFtpClient.cs`
|
||||
- Main implementation: `Cnc/Siemens/SiemensMachine.cs`
|
||||
- Config: `Cnc/Siemens/SiemensConnectionConfig.cs`
|
||||
- Requirement: Sinumerik FTP option must be enabled on machine
|
||||
|
||||
**Mitsubishi M-Series FTP:**
|
||||
- Used for: Program transfer to/from Mitsubishi M-series controllers
|
||||
- Protocol: Standard FTP (RFC 959) via `System.Net.FtpWebRequest`
|
||||
- Default port: 21
|
||||
- Default program dir: `/PRG/`
|
||||
- Auth: Username + password
|
||||
- Client: `Cnc/Mitsubishi/MitsubishiFtpClient.cs`
|
||||
- Main implementation: `Cnc/Mitsubishi/MitsubishiMachine.cs`
|
||||
- Config: `Cnc/Mitsubishi/MitsubishiConnectionConfig.cs`
|
||||
|
||||
## Licensing System
|
||||
|
||||
**RSA Offline License Validation:**
|
||||
- Used for: Binding license to specific machine hardware
|
||||
- Mechanism: RSA-SHA256 signature verification
|
||||
- Public key: Embedded as const string in `Licensing/LicenseValidator.cs`
|
||||
- Private key: Vendor-only, stored at `~/Documents/mine/c#/LicenseGenerator/private.key.xml` (gitignored)
|
||||
- Machine fingerprint: WMI queries (CPU ID + motherboard serial) via `Licensing/MachineFingerprint.cs`
|
||||
- License file: `license.lic` (Base64-encoded RSA signature) next to EXE
|
||||
- Crypto: `RSACryptoServiceProvider` + `SHA256CryptoServiceProvider` (.NET 4.7.2 compatible)
|
||||
- Generator tool: Separate repo `ssh://git@3nt-git.duckdns.org:222/davide.trentin/license-generator.git`
|
||||
|
||||
## Hardware Access
|
||||
|
||||
**WMI (Windows Management Instrumentation):**
|
||||
- Used for: Machine fingerprinting in licensing
|
||||
- Queries: `Win32_Processor` (processorID), `Win32_BaseBoard` (SerialNumber)
|
||||
- Package: `System.Management 7.0.1`
|
||||
- Files: `Licensing/MachineFingerprint.cs`
|
||||
- Platform: Windows only
|
||||
|
||||
## Data Storage
|
||||
|
||||
**File System (local):**
|
||||
- NC program files written/read from local path specified via `-pathprogramma=` CLI arg
|
||||
- License file read from `AppDomain.CurrentDomain.BaseDirectory`
|
||||
- No database, no cloud storage
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
- No error tracking service (Sentry, etc.)
|
||||
- No analytics
|
||||
- Logging: `Console.WriteLine` only (no structured logging framework)
|
||||
|
||||
---
|
||||
|
||||
*Integrations analysis: 2026-05-18*
|
||||
*Update when new protocols or services are added*
|
||||
83
.paul/codebase/STACK.md
Normal file
83
.paul/codebase/STACK.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Technology Stack
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## Languages
|
||||
|
||||
**Primary:**
|
||||
- C# (.NET Framework 4.7.2) - All application code
|
||||
|
||||
**Secondary:**
|
||||
- XML - Project files, App.config, binding redirects
|
||||
|
||||
## Runtime
|
||||
|
||||
**Environment:**
|
||||
- .NET Framework 4.7.2 — Windows only (FOCAS1 DLL + WMI)
|
||||
- No cross-platform support; Windows desktop/server target
|
||||
|
||||
**Package Manager:**
|
||||
- NuGet (packages.config format, not PackageReference)
|
||||
- Lockfile: `packages.config` present in root and test project
|
||||
|
||||
## Frameworks
|
||||
|
||||
**Core:**
|
||||
- None (vanilla .NET console application)
|
||||
|
||||
**Testing:**
|
||||
- NUnit 3.13.3 — Unit and integration tests (`NcProgramManager.Tests/packages.config`)
|
||||
- NUnit3TestAdapter 4.2.1 — VS / dotnet test runner
|
||||
- Moq 4.18.4 — Interface mocking
|
||||
|
||||
**Build/IL Weaving:**
|
||||
- Fody 6.6.4 — IL code weaver (`NcProgramManager.csproj`)
|
||||
- Costura.Fody 5.7.0 — Embeds NuGet assemblies + native DLLs into output EXE
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
**Critical:**
|
||||
- `System.Management 7.0.1` — WMI queries for machine fingerprinting (`Licensing/MachineFingerprint.cs`)
|
||||
- `Microsoft.Bcl.AsyncInterfaces 7.0.0` — Async backport for .NET 4.7.2 (`packages.config`)
|
||||
- `System.Memory 4.5.5` — Span<T> and Memory<T> compatibility (`packages.config`)
|
||||
- `System.Runtime.CompilerServices.Unsafe 6.0.0` — Low-level ops (`packages.config`)
|
||||
- `System.Net.Sockets 4.3.0` — TCP networking for LSV2/FTP (`packages.config`)
|
||||
|
||||
**Infrastructure:**
|
||||
- `NETStandard.Library 2.0.3` — .NET Standard facade (`packages.config`)
|
||||
- `System.Net.Http 4.3.4` — HTTP base infrastructure (`packages.config`)
|
||||
- `Castle.Core 5.1.1` — Moq dependency (`NcProgramManager.Tests/packages.config`)
|
||||
|
||||
**Native (embedded via Costura.Fody):**
|
||||
- `Cnc/Fanuc/libs/Fwlib32.dll` — Fanuc FOCAS1 library (32-bit, ~629KB)
|
||||
- `Cnc/Fanuc/libs/fwlibe1.dll` — Extended FOCAS (~1MB)
|
||||
- `Cnc/Fanuc/libs/fwlibNCG.dll` — FOCAS NCG support (~2MB)
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment:**
|
||||
- No environment variables
|
||||
- All runtime config passed via CLI arguments (parsed by `ArgParser.cs`)
|
||||
- License file: `license.lic` next to EXE (no CLI override)
|
||||
|
||||
**Build:**
|
||||
- `NcProgramManager.csproj` — MSBuild 15.0, OutputType=Exe
|
||||
- `App.config` — Runtime binding redirects only (no business settings)
|
||||
- `FodyWeavers.xml` — Costura assembly embedding config
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
**Development:**
|
||||
- Windows (FOCAS1 DLL requires 32-bit Windows; WMI for licensing)
|
||||
- Visual Studio 2017+ or MSBuild 15+
|
||||
- Fanuc FOCAS DLL unavailable on Linux (test suite ignores FOCAS tests)
|
||||
|
||||
**Production:**
|
||||
- Windows (desktop or server)
|
||||
- `license.lic` placed alongside EXE
|
||||
- 32-bit process or AnyCPU with 32-bit preferred (FOCAS1 DLL constraint)
|
||||
|
||||
---
|
||||
|
||||
*Stack analysis: 2026-05-18*
|
||||
*Update after major dependency changes*
|
||||
160
.paul/codebase/STRUCTURE.md
Normal file
160
.paul/codebase/STRUCTURE.md
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
# Codebase Structure
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
nc_program_manager/
|
||||
├── NcProgramManager/ # Main application
|
||||
│ ├── Program.cs # CLI entry point, action dispatch
|
||||
│ ├── ArgParser.cs # CLI argument parser
|
||||
│ ├── InputArgs.cs # Parsed args config object
|
||||
│ ├── FanucProgram.cs # Fanuc composite NC file parser
|
||||
│ ├── fwlib32.cs # Fanuc FOCAS1 P/Invoke wrapper (auto-gen, 11K lines)
|
||||
│ ├── NcProgramManager.csproj # Project file (.NET 4.7.2, Console)
|
||||
│ ├── App.config # Runtime binding redirects
|
||||
│ ├── packages.config # NuGet dependencies
|
||||
│ ├── Licensing/ # License validation subsystem
|
||||
│ ├── Cnc/ # CNC abstraction + implementations
|
||||
│ │ ├── ICncMachine.cs
|
||||
│ │ ├── IFanucMachine.cs
|
||||
│ │ ├── INcProgramValidator.cs
|
||||
│ │ ├── NcProgramValidator.cs
|
||||
│ │ ├── CncMachineFactory.cs
|
||||
│ │ ├── Models/ # DTOs and value objects
|
||||
│ │ ├── Fanuc/ # FOCAS protocol
|
||||
│ │ │ └── libs/ # Native DLLs (embedded)
|
||||
│ │ ├── Heidenhain/ # LSV2 protocol
|
||||
│ │ ├── Siemens/ # FTP protocol
|
||||
│ │ └── Mitsubishi/ # FTP protocol
|
||||
│ └── Properties/
|
||||
│ └── AssemblyInfo.cs
|
||||
├── NcProgramManager.Tests/ # Test suite
|
||||
│ ├── Unit/ # Isolated unit tests
|
||||
│ ├── Integration/ # Protocol integration tests
|
||||
│ │ └── Stubs/ # In-process server stubs
|
||||
│ ├── NcProgramManager.Tests.csproj
|
||||
│ ├── packages.config
|
||||
│ └── nunit.runsettings
|
||||
├── NcProgramManager.sln # Solution file
|
||||
├── Dockerfile.test # Containerized test runner
|
||||
└── README.md # Italian operator docs
|
||||
```
|
||||
|
||||
## Directory Purposes
|
||||
|
||||
**`Licensing/`:**
|
||||
- Purpose: RSA-based offline license validation
|
||||
- Key files: `LicenseValidator.cs`, `MachineFingerprint.cs`, `LicenseFile.cs`, `ILicenseValidator.cs`, `IMachineFingerprint.cs`
|
||||
|
||||
**`Cnc/Models/`:**
|
||||
- Purpose: Shared DTOs and value objects for CNC layer
|
||||
- Key files: `CncResult.cs`, `CncError.cs`, `CncManufacturer.cs`, `CncProgram.cs`, `ConnectionState.cs`, `ValidationError.cs`, `ValidationResult.cs`, `ValidationSeverity.cs`, `MachineSnapshot.cs`, `MachineMode.cs`, `MotionState.cs`, `RunState.cs`
|
||||
|
||||
**`Cnc/Fanuc/`:**
|
||||
- Purpose: Fanuc FOCAS protocol implementation
|
||||
- Key files: `FanucMachine.cs` (main), `FanucConnectionConfig.cs`, `IFocasDialect.cs`, `LegacyFocasDialect.cs`, `ModernFocasDialect.cs`, `FocasDialectFactory.cs`, `FanucDialectDetector.cs`, `FanucErrorTranslator.cs`, `IsoProgramFormatter.cs`, `FanucCapabilities.cs`, `FanucTransport.cs`
|
||||
|
||||
**`Cnc/Heidenhain/`:**
|
||||
- Purpose: Heidenhain LSV2 protocol implementation
|
||||
- Key files: `HeidenhainMachine.cs`, `Lsv2Client.cs`, `ILsv2Client.cs`, `HeidenhainConnectionConfig.cs`
|
||||
|
||||
**`Cnc/Siemens/`:**
|
||||
- Purpose: Siemens FTP protocol implementation
|
||||
- Key files: `SiemensMachine.cs`, `SiemensFtpClient.cs`, `ISiemensFtpClient.cs`, `SiemensConnectionConfig.cs`
|
||||
|
||||
**`Cnc/Mitsubishi/`:**
|
||||
- Purpose: Mitsubishi FTP protocol implementation
|
||||
- Key files: `MitsubishiMachine.cs`, `MitsubishiFtpClient.cs`, `IMitsubishiFtpClient.cs`, `MitsubishiConnectionConfig.cs`
|
||||
|
||||
**`NcProgramManager.Tests/Unit/`:**
|
||||
- Purpose: Isolated unit tests with mocks
|
||||
- Key files: `NcProgramValidatorTests.cs`, `FanucMachineTests.cs`, `FanucProgramParsingTests.cs`, `IsoProgramFormatterTests.cs`, `CncMachineFactoryTests.cs`, `LicenseValidatorTests.cs`, `SiemensMachineTests.cs`, `MitsubishiMachineTests.cs`, `HeidenhainMachineTests.cs`
|
||||
|
||||
**`NcProgramManager.Tests/Integration/`:**
|
||||
- Purpose: Protocol-level tests using in-process stubs
|
||||
- Key files: `HeidenhainMachineIntegrationTests.cs`, `SiemensMachineIntegrationTests.cs`, `MitsubishiMachineIntegrationTests.cs`
|
||||
|
||||
**`NcProgramManager.Tests/Integration/Stubs/`:**
|
||||
- Purpose: In-process server stubs for protocol testing
|
||||
- Key files: `FtpServerStub.cs` (FTP server with in-memory file store), `Lsv2ServerStub.cs` (LSV2 TCP server)
|
||||
|
||||
## Key File Locations
|
||||
|
||||
**Entry Points:**
|
||||
- `Program.cs` — Main(), CLI orchestration, exit codes
|
||||
- `ArgParser.cs` — static `Parse(string[]) → InputArgs`
|
||||
|
||||
**Configuration:**
|
||||
- `NcProgramManager.csproj` — Project metadata, NuGet refs, build config
|
||||
- `App.config` — Binding redirects only
|
||||
- `packages.config` — NuGet dependency list
|
||||
|
||||
**Core Logic:**
|
||||
- `Cnc/ICncMachine.cs` — Primary abstraction interface
|
||||
- `Cnc/CncMachineFactory.cs` — Manufacturer dispatch
|
||||
- `Cnc/Models/CncResult.cs` — Result wrapper pattern
|
||||
- `Cnc/Fanuc/FanucMachine.cs` — Largest impl (~740 lines)
|
||||
- `Licensing/LicenseValidator.cs` — License check entry
|
||||
|
||||
**Testing:**
|
||||
- `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs` — Most comprehensive unit tests
|
||||
- `NcProgramManager.Tests/Integration/Stubs/FtpServerStub.cs` — Reusable FTP stub
|
||||
|
||||
**Documentation:**
|
||||
- `README.md` — Italian operator-facing docs (CLI args, license setup, error codes)
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Files:**
|
||||
- PascalCase for all `.cs` files: `FanucMachine.cs`, `CncResult.cs`
|
||||
- Interfaces prefixed with I: `ICncMachine.cs`, `IFocasDialect.cs`
|
||||
- Config classes: `{Manufacturer}ConnectionConfig.cs`
|
||||
- Test files: `{Subject}Tests.cs` or `{Subject}IntegrationTests.cs`
|
||||
|
||||
**Directories:**
|
||||
- PascalCase for manufacturer dirs: `Fanuc/`, `Heidenhain/`, `Siemens/`, `Mitsubishi/`
|
||||
- Lowercase for support: `libs/`
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New CNC manufacturer:**
|
||||
- Implementation: `Cnc/{Manufacturer}/{Manufacturer}Machine.cs` (implement `ICncMachine`)
|
||||
- Config: `Cnc/{Manufacturer}/{Manufacturer}ConnectionConfig.cs`
|
||||
- Client: `Cnc/{Manufacturer}/I{Manufacturer}FtpClient.cs` + `{Manufacturer}FtpClient.cs` (if FTP)
|
||||
- Wire: Add case to `Cnc/CncMachineFactory.cs`
|
||||
- Enum: Add value to `Cnc/Models/CncManufacturer.cs`
|
||||
- Args: Update `ArgParser.cs` if new transport args needed
|
||||
|
||||
**New Fanuc FOCAS feature:**
|
||||
- Add to `Cnc/Fanuc/IFocasDialect.cs`, implement in `LegacyFocasDialect.cs` + `ModernFocasDialect.cs`
|
||||
- Surface in `Cnc/Fanuc/FanucMachine.cs`
|
||||
- If Fanuc-specific CLI exposure: update `IFanucMachine.cs`, `Program.cs`
|
||||
|
||||
**New validation rule:**
|
||||
- Add to `Cnc/NcProgramValidator.cs`
|
||||
- Add test to `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs`
|
||||
|
||||
**New CLI arg:**
|
||||
- Add to `ArgParser.cs` regex parsing
|
||||
- Add field to `InputArgs.cs`
|
||||
- Update `README.md` params table
|
||||
|
||||
## Special Directories
|
||||
|
||||
**`Cnc/Fanuc/libs/`:**
|
||||
- Purpose: Native Fanuc FOCAS DLLs
|
||||
- Source: Fanuc-provided proprietary binaries
|
||||
- Committed: Yes (required for build)
|
||||
- Embedded: Via Costura.Fody into output EXE
|
||||
|
||||
**`.paul/`:**
|
||||
- Purpose: PAUL project planning state
|
||||
- Source: Generated/maintained by PAUL workflow
|
||||
- Committed: Yes
|
||||
|
||||
---
|
||||
|
||||
*Structure analysis: 2026-05-18*
|
||||
*Update when directory structure changes*
|
||||
153
.paul/codebase/TESTING.md
Normal file
153
.paul/codebase/TESTING.md
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** 2026-05-18
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Runner:**
|
||||
- NUnit 3.13.3 — `NcProgramManager.Tests/packages.config`
|
||||
- NUnit3TestAdapter 4.2.1 — VS/dotnet test runner integration
|
||||
- Config: `NcProgramManager.Tests/nunit.runsettings`
|
||||
|
||||
**Assertion Library:**
|
||||
- NUnit fluent API: `Assert.That(actual, Is.True)`, `Is.EqualTo()`, `Is.InstanceOf<T>()`
|
||||
|
||||
**Mocking:**
|
||||
- Moq 4.18.4 for interface mocking
|
||||
- Castle.Core 5.1.1 (Moq dependency)
|
||||
- Custom delegates for `ref` parameter workaround (Moq limitation with P/Invoke refs)
|
||||
- Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs`
|
||||
|
||||
**Run Commands:**
|
||||
```bash
|
||||
# Standard NUnit runner or VS Test Explorer
|
||||
dotnet test NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||
# Or via Dockerfile:
|
||||
docker build -f Dockerfile.test .
|
||||
```
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Location:**
|
||||
- All tests in `NcProgramManager.Tests/` (separate project)
|
||||
- Unit tests: `NcProgramManager.Tests/Unit/`
|
||||
- Integration tests: `NcProgramManager.Tests/Integration/`
|
||||
- Stubs: `NcProgramManager.Tests/Integration/Stubs/`
|
||||
|
||||
**Naming:**
|
||||
- Unit: `{Subject}Tests.cs` — `NcProgramValidatorTests.cs`, `FanucMachineTests.cs`
|
||||
- Integration: `{Subject}IntegrationTests.cs` — `HeidenhainMachineIntegrationTests.cs`
|
||||
- Stubs: `{Protocol}ServerStub.cs` — `FtpServerStub.cs`, `Lsv2ServerStub.cs`
|
||||
|
||||
## Test Structure
|
||||
|
||||
**Fixture Pattern:**
|
||||
```csharp
|
||||
[TestFixture]
|
||||
public class NcProgramValidatorTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() { ... }
|
||||
|
||||
[Test]
|
||||
public void MethodName_Condition_ExpectedResult()
|
||||
{
|
||||
// arrange
|
||||
// act
|
||||
// assert (NUnit fluent)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Parameterized Tests:**
|
||||
```csharp
|
||||
[TestCase(CncManufacturer.Fanuc)]
|
||||
[TestCase(CncManufacturer.Siemens)]
|
||||
[TestCase(CncManufacturer.Heidenhain)]
|
||||
[TestCase(CncManufacturer.Mitsubishi)]
|
||||
public void Validate_TabCharacter_ReturnsWarning(CncManufacturer m) { ... }
|
||||
```
|
||||
Example: `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs`
|
||||
|
||||
**Async Tests:**
|
||||
- No `async Task` test methods — use `.GetAwaiter().GetResult()` to block
|
||||
- Example: `NcProgramManager.Tests/Integration/HeidenhainMachineIntegrationTests.cs`
|
||||
|
||||
**Test Categories:**
|
||||
```csharp
|
||||
[Category("Integration")] // marks integration tests
|
||||
```
|
||||
|
||||
## Mocking
|
||||
|
||||
**Interface mocking via Moq:**
|
||||
```csharp
|
||||
var mockDialect = new Mock<IFocasDialect>();
|
||||
mockDialect.Setup(d => d.Connect(...)).Returns(...);
|
||||
var machine = new FanucMachine(config, mockDialect.Object);
|
||||
```
|
||||
Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs`
|
||||
|
||||
**Reflection-based state injection (for bypassing protected fields):**
|
||||
```csharp
|
||||
// Set internal connection state without real hardware
|
||||
typeof(FanucMachine)
|
||||
.GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.SetValue(machine, ConnectionState.Connected);
|
||||
```
|
||||
Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs`
|
||||
|
||||
**What to mock:**
|
||||
- Protocol interfaces: `IFocasDialect`, `ILsv2Client`, `ISiemensFtpClient`, `IMitsubishiFtpClient`
|
||||
- Licensing: `IMachineFingerprint`, `ILicenseValidator`
|
||||
|
||||
## In-Process Protocol Stubs
|
||||
|
||||
**FtpServerStub** (`NcProgramManager.Tests/Integration/Stubs/FtpServerStub.cs`):
|
||||
- Minimal FTP server for Siemens/Mitsubishi integration testing
|
||||
- In-memory file store: `Dictionary<string, string> Files`
|
||||
- Supported commands: USER, PASS, CWD, TYPE, PASV, LIST, NLST, RETR, STOR, DELE
|
||||
- Usage: Start before test, inject port into machine config
|
||||
|
||||
**Lsv2ServerStub** (`NcProgramManager.Tests/Integration/Stubs/Lsv2ServerStub.cs`):
|
||||
- Minimal LSV2 TCP server for Heidenhain integration testing
|
||||
- Implements LSV2 framing (STX, SIZE, CMD, data, CRC)
|
||||
- Thread-per-client architecture
|
||||
|
||||
## Ignored Tests
|
||||
|
||||
**FOCAS DLL-dependent tests marked `[Ignore]`:**
|
||||
- All tests requiring actual `Fwlib32.dll` calls are ignored
|
||||
- Reason: Cannot mock static P/Invoke calls; DLL requires real Fanuc hardware on Windows
|
||||
- Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs`
|
||||
|
||||
**Pattern for skipping:**
|
||||
```csharp
|
||||
[Test]
|
||||
[Ignore("Requires Fanuc FOCAS DLL and real hardware")]
|
||||
public void ConnectAsync_ValidConfig_Connects() { ... }
|
||||
```
|
||||
|
||||
## Coverage Approach
|
||||
|
||||
**Well-covered:**
|
||||
- `NcProgramValidator` — universal rules + all 4 manufacturers, 30+ test cases
|
||||
- `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs`
|
||||
- `FanucProgram` parsing — `FanucProgramParsingTests.cs`
|
||||
- `IsoProgramFormatter` — `IsoProgramFormatterTests.cs`
|
||||
- `CncMachineFactory` dispatch — `CncMachineFactoryTests.cs`
|
||||
- `LicenseValidator` — 6 unit tests via internal ctor injection — `LicenseValidatorTests.cs`
|
||||
|
||||
**Partially covered (blocked by hardware):**
|
||||
- `FanucMachine` connect/read/write — FOCAS tests `[Ignore]`d
|
||||
- Heidenhain/Siemens/Mitsubishi machines — integration tests use stubs
|
||||
|
||||
**Not covered:**
|
||||
- `MachineFingerprint` (WMI, Windows-only, no mocked tests)
|
||||
- `LicenseFile` parsing edge cases
|
||||
- `Program.cs` CLI orchestration (no CLI-level tests)
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: 2026-05-18*
|
||||
*Update when test framework or patterns change*
|
||||
Loading…
Add table
Reference in a new issue