
# Test Stratejisi

merql, oracle tabanlı bir test modeli kullanır. Her test senaryosu bilinen bir girdi kümesi (üç veritabanı durumu) ve belirlenimci bir beklenen sonuç (oracle) tanımlar; ardından gerçek birleştirme çıktısını bu beklentiyle karşılaştırır. 32 senaryo; temiz birleştirmeleri, çakışmaları, kimlik çözümlemeyi, veri türlerini, ölçeği ve uç durumları kapsar.

```bash
# Run the full verification suite.
./bin/verify-all
```

Bu sayfadaki komutlar, merql deposunun bir çalışma kopyasında `composer install` sonrasında çalıştırılır. `bin/` içindeki geliştirme betikleri, `scenarios/` külliyatı ve testler Composer paketinin parçası değildir. Geliştirme bağımlılıkları PHP 8.4 veya üzerini gerektiren PHPUnit 13'ü içerir; kütüphanenin kendisi PHP 8.2'de çalışsa da.

## Oracle tabanlı testler

Üç yönlü veritabanı birleştirmesi yapan mevcut bir referans aracı olmadığından oracle, harici bir araç tarafından üretilmek yerine bilinen girdilerden hesaplanır. Her senaryonun mantık yoluyla doğrulanabilen belirlenimci bir beklenen sonucu vardır:

1. **Kurulum** -- bilinen içeriklerle üç veritabanı durumu (base, ours, theirs) oluşturun.
2. **Oracle** -- bilinen girdilerden beklenen birleştirme sonucunu hesaplayın.
3. **Gerçek sonuç** -- merql ile üç durum üzerinde birleştirmeyi çalıştırın.
4. **Karşılaştırma** -- gerçek sonuç, beklenen sonuçla tam olarak eşleşmelidir.

```
Known inputs (base, ours, theirs)
         |                    |
    Deterministic          merql merge
    computation
         |                    |
    Expected result       Actual result
         |                    |
         -----> Compare <-----
                  |
            Pass or Fail
```

## Testleri çalıştırma

### Tam doğrulama

`verify-all` betiği son kontroldür. Statik analizi, kodlama standartlarını, PHPUnit testlerini ve oracle regresyon paketini çalıştırır:

```bash
./bin/verify-all
```

Herhangi bir çalışma tamamlanmış sayılmadan önce bu kontroller geçmelidir.

### Oracle regresyon paketi

32 senaryonun tümünü çalıştırın:

```bash
./bin/test-regression
```

Tek bir kategoriyi çalıştırın:

```bash
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity
```

Kategoriler, `scenarios/` altındaki dizin adlarıdır: `clean`, `conflict`,
`identity`, `types`, `scale` ve `edge`. Bilinmeyen bir kategori `No scenarios found` çıktısını verir
ve başarıyla çıkar. Birden fazla kategoriyi çalıştırmak için `--category` yinelenebilir.

Betik `--jobs` seçeneğini de kabul eder ancak değeri yok sayıp senaryoları
sırayla çalıştırır ([#5](https://github.com/inline0/merql/issues/5)).

En az çıktıyla çalıştırın (yalnızca başarılı/başarısız):

```bash
./bin/test-regression --fast
```

### Tek senaryo

Tam işlem hattı üzerinden tek bir senaryoyu test edin:

```bash
./bin/test-scenario column-level-clean
```

### Tek tek oracle adımları

```bash
./bin/oracle column-level-clean    # Compute expected result
./bin/actual column-level-clean    # Run merql, capture output
./bin/compare column-level-clean   # Diff oracle vs actual
```

### Birim testleri

```bash
composer test:unit         # Isolated component tests
composer test:integration  # Integration tests (SQLite, plus MySQL when configured)
composer test              # All PHPUnit suites
composer test:oracle       # Oracle regression corpus (bin/test-regression)
composer verify            # analyse + cs + test + test:oracle
```

`composer test` yalnızca PHPUnit çalıştırır. `oracle` PHPUnit paketi, senaryo çalıştırıcı sınıflarını barındıran ancak test vakası içermeyen `tests/Oracle` konumunu kullanır; bu nedenle 32 senaryo yalnızca `composer test:oracle`, `composer verify` veya `./bin/verify-all` aracılığıyla çalıştırılır.

`MERQL_MYSQL_HOST`, `MERQL_MYSQL_DATABASE` ve `MERQL_MYSQL_USER` (isteğe bağlı olarak `MERQL_MYSQL_PASSWORD` ve `MERQL_MYSQL_PORT` ile birlikte) bir test veritabanını göstermedikçe MySQL entegrasyon testleri atlanır.

### Kod kalitesi

```bash
composer cs            # PSR-12 coding standards check
composer cs:fix        # Auto-fix coding standards
composer analyse       # PHPStan level 10 static analysis
```

## Senaryo kategorileri

### clean (8 senaryo)

Çakışma içermeyen temiz birleştirmeler. İki taraf da veriyi değiştirebilir, ancak aynı satırın aynı sütununu asla değiştirmez.

| Senaryo | Testler |
|---|---|
| `insert-only-theirs` | Theirs satır ekledi, ours değiştirmedi. |
| `update-only-theirs` | Theirs satırları güncelledi, ours değiştirmedi. |
| `delete-only-theirs` | Theirs satırları sildi, ours değiştirmedi. |
| `insert-only-ours` | Ours satır ekledi, theirs değiştirmedi. |
| `mixed-no-overlap` | İki taraf da farklı tabloları veya satırları değiştirdi. |
| `both-same-change` | İki taraf da aynı değişiklikleri yaptı (çakışma yok). |
| `column-level-clean` | İki taraf da aynı satırda farklı sütunları değiştirdi. |
| `multi-table` | Birden fazla tabloda yapılan değişiklikler. |

### conflict (6 senaryo)

Çakışma oluşturması gereken senaryolar.

| Senaryo | Testler |
|---|---|
| `both-update-same-column` | İki taraf da aynı sütunu farklı değerlere değiştirdi. |
| `update-vs-delete` | Bir taraf aynı satırı güncelledi, diğeri sildi. |
| `delete-vs-update` | Güncelleme-silme işleminin tersi. |
| `both-insert-same-pk` | İki taraf da aynı birincil anahtara sahip satır ekledi. |
| `multiple-conflicts` | Tek bir birleştirmede birden fazla çakışma. |
| `partial-conflict` | Bazı sütunlar çakışırken diğerleri sorunsuz birleşir. |

### identity (4 senaryo)

Satır kimliğinin uç durumları.

| Senaryo | Testler |
|---|---|
| `auto-increment` | Yeni satırların dallar arasında farklı kimlikleri vardır. |
| `natural-key` | Birincil anahtar yerine benzersiz sütunlara göre eşleştirme. |
| `composite-key` | Çok sütunlu birincil anahtar. |
| `no-key` | Birincil anahtarı olmayan tablo (içerik özeti yedeği). |

### types (6 senaryo)

Tüm sütun türlerinde veri türü işleme.

| Senaryo | Testler |
|---|---|
| `text-columns` | VARCHAR, TEXT, LONGTEXT değerleri. |
| `numeric-columns` | INT, DECIMAL, FLOAT değerleri. |
| `date-columns` | DATE, DATETIME, TIMESTAMP değerleri. |
| `json-columns` | JSON sütun birleştirmesi. |
| `blob-columns` | İkili veri. |
| `null-handling` | NULL'dan değere, değerden NULL'a geçişler. |

### scale (4 senaryo)

Yük altındaki performans.

| Senaryo | Testler |
|---|---|
| `1k-rows` | 1,000 satır. |
| `10k-rows` | 10,000 satır. |
| `100k-rows` | 100,000 satır. |
| `wide-table` | 50+ sütunlu tablo. |

### edge (4 senaryo)

Uç durumlar ve sınır koşulları.

| Senaryo | Testler |
|---|---|
| `empty-changeset` | Bir veya iki tarafta da değişiklik yok. |
| `schema-mismatch` | Anlık görüntüler arasında sütun ekleme veya kaldırma. |
| `encoding` | UTF-8, emoji ve özel karakterler. |
| `large-text` | Çok büyük TEXT/LONGTEXT değerleri. |

## Senaryo yapısı

Her senaryo, `scenario.json` yapılandırma dosyasını içeren `scenarios/<category>/<name>/` altında bir dizindir:

```json
{
    "name": "column-level-clean",
    "category": "clean",
    "description": "Both sides modify same row but different columns",
    "tables": ["test_posts"],
    "expectations": {
        "conflicts": 0,
        "operations": 3,
        "changeset_match": "exact",
        "merge_match": "exact",
        "sql_match": "semantic"
    }
}
```

Çakışma senaryolarında beklenen çakışmalar ayrıntılı olarak belirtilir:

```json
{
    "expectations": {
        "conflicts": 1,
        "conflict_details": [
            {
                "table": "test_posts",
                "primary_key": {"id": 42},
                "column": "title",
                "ours_value": "Welcome",
                "theirs_value": "Greetings"
            }
        ]
    }
}
```

## ScenarioRunner işlem hattı

`ScenarioRunner::run()` tek bir senaryoyu düzenler:

1. `OracleCapture::compute()`, senaryonun JSON verilerinden üç anlık görüntü oluşturur ve birleştirmeyi çalıştırır.
2. `ScenarioComparator::compare()`, birleştirme sonucunu `scenario.json` içindeki beklenen değerlerle karşılaştırır.
3. Başarılı/başarısız sonucunu ve hata mesajlarının listesini döndürür.

```php
use Merql\Tests\Oracle\ScenarioRunner;

$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
```

`ScenarioRunner::runAll()` her senaryoyu sırayla çalıştırır:

```php
$results = ScenarioRunner::runAll($scenarios);
```

## Yeni senaryo ekleme

1. Bir dizin oluşturun: `scenarios/<category>/<name>/`.
2. Senaryo meta verilerini ve beklentileri içeren `scenario.json` dosyasını oluşturun.
3. JSON yapılandırmasında üç veritabanı durumunu tanımlayın: base verileri, ours değişiklikleri, theirs değişiklikleri.
4. Senaryoyu çalıştırın: `./bin/test-scenario <name>`.
5. Paketin tamamını doğrulayın: `./bin/verify-all`.

## Kod kalitesi standartları

merql şu standartları uygular:

- **PHPStan düzey 10** -- taban istisnaları olmadan sıkı statik analiz.
- **PSR-12** -- kodlama standartları `phpcs` tarafından denetlenir.
- **Oracle regresyonu** -- 32 senaryonun tümü geçmelidir.
- **Birim testleri** -- her bileşen için yalıtılmış testler.

`verify-all` betiği dört kontrolün tümünü sırayla çalıştırır. Kısmi onay kabul edilmez.

## Sürekli entegrasyon

CI; kodlama standartlarını, PHPStan, `composer test`, MySQL 8.4'e karşı mysqli kullanan entegrasyon paketini, birleştirme temel işlemlerinin kapsamını ve `composer audit` öğesini `main` deposuna yapılan her gönderimde ve çekme isteğinde çalıştırır. Oracle regresyon külliyatını ([#6](https://github.com/inline0/merql/issues/6)) çalıştırmaz; bu nedenle bir değişikliğe güvenmeden önce yerel olarak `composer test:oracle` veya `./bin/verify-all` çalıştırın.
