# Build and Test

## Build

From the **repo root**:

```bat
dotnet build SyncEngine.sln -c Release
```

Output:

```
SyncEngine\bin\Release\net48\SyncEngine.exe
```

### Debug build

```bat
dotnet build SyncEngine.sln -c Debug
```

Output: `SyncEngine\bin\Debug\net48\SyncEngine.exe`

### x86 build (32-bit ACE only)

The default `PlatformTarget` is **x64** in both `SyncEngine.csproj` and `SyncEngine.Tests.csproj`.

If only 32-bit ACE OLEDB is installed, change:

```xml
<PlatformTarget>x86</PlatformTarget>
```

Then rebuild. Set `SYNC_PLATFORM_TARGET=x86` in `.env` for documentation consistency.

## Output artifacts

After a Release build, `SyncEngine\bin\Release\net48\` contains:

| Artifact | Source |
|----------|--------|
| `SyncEngine.exe` | Compiled executable |
| `App.config` | Binding redirects |
| `config\` | Copied from repo `config\` (includes `product-sync-map.json`, `.env.example`) |
| `.env` | Copied from repo root **if it exists at build time** |
| `*.dll` | NuGet dependencies (SqlClient, MySqlConnector, Serilog, Polly, Newtonsoft.Json) |

### Config copy behavior

Defined in `SyncEngine.csproj`:

- `config\**\*` — linked and copied on every build (`PreserveNewest`)
- Repo-root `.env` — copied via the `CopyEnvToOutput` MSBuild target after each build

The output directory is wiped on rebuild, so always maintain `.env` at the repo root (or beside the exe for deployment-only edits).

## Run

```bat
SyncEngine\bin\Release\net48\SyncEngine.exe all
```

Or `cd` into the output directory and run `SyncEngine.exe` directly.

Only one `SyncEngine.exe` process may run on a machine at a time. A second start exits with code **3** (see [Exit codes](#exit-codes)).

## Exit codes

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Runtime/sync failure |
| 2 | Configuration error |
| 3 | Another instance already running |

See [getting-started.md](getting-started.md#exit-code-3--another-instance-running) for Task Scheduler overlap and troubleshooting.

## Tests

From the repo root:

```bat
dotnet test SyncEngine.sln -c Release
```

### Test scope

Unit tests in `SyncEngine.Tests` cover:

| Area | Test class | Examples |
|------|------------|----------|
| View translation | `SqlViewTranslatorTests` | Access SQL → T-SQL |
| SQL identifiers | `SqlIdentifierHelperTests` | Bracket-quoting, schema qualification |
| Schema keys | `SqlSchemaKeyBuilderTests` | PK/index DDL, filtered unique indexes |
| Identity | `SqlIdentityHelperTests` | Staging table names, CHECKIDENT literal |
| Access types | `AccessTypeMapperTests` | CLR → SQL types, IDENTITY columns |
| Access defaults | `AccessDefaultTranslatorTests` | `Now()`, Yes/No, date literals |
| Access validation | `AccessValidationTranslatorTests` | `>=0`, `Is Not Null` |
| Index grouping | `AccessIndexGrouperTests` | Composite `MSysIndexes` rows |
| Table exclusions | `TableExcludeFilterTests` | Parse/filter tables, FKs, indexes |
| Product mapping | `ProductFieldMapperTests` | Truncate, slug, price |
| MySQL product sync | `MySqlProductSyncTests` | INSERT/UPDATE SQL includes `sqlexpress_product_id`; `productIdColumn` config |
| Change detection | `ChangeDetectorTests` | Row hash normalization |
| Sync statistics | `SyncStatisticsTests` | Summary format (`pksUnchanged`, `pksSkipped=0`) |
| Options validation | `SyncOptionsValidatorTests` | Placeholder detection, mode requirements |
| Single-instance guard | `SyncInstanceLockTests` | Mutex acquire, block, release |
| MySQL connection | `MySqlConnectionFailuresTests` | Reconnectable error classification |
| Shop sync log | `ShopSyncLogClientTests`, `ShopSyncLogClientFallbackTests`, `ShopSyncLogApiClientTests`, `ShopSyncLogLocalWriterTests` | MySQL write, API fallback, local JSONL |

Tests do **not** connect to live Access, SQL Express, or MySQL databases. Integration testing requires a configured environment — see [getting-started.md](getting-started.md).

## Solution structure

```
SyncEngine.sln
├── SyncEngine/           # Main executable (net48)
└── SyncEngine.Tests/     # xUnit-style unit tests (net48)
```

## Related

- [getting-started.md](getting-started.md) — setup and first run
- [configuration.md](configuration.md) — `.env` reference
- [access-sql-express-compatibility.md](access-sql-express-compatibility.md) — Access → SQL Express schema mirroring
