بنقرة واحدة
tdd
Test-first workflow for features, bug fixes, refactors, and project-specific test patterns.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Test-first workflow for features, bug fixes, refactors, and project-specific test patterns.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Use this skill to generate well-branded interfaces and assets for RIPDPI (an Android-native, Compose-first VPN and DPI-bypass app), either for production or throwaway prototypes/mocks/etc. Contains essential design guidelines, colors, type, fonts, brand-ship icons, and an interactive UI kit of every public composable from the live ui/components tree.
Use when managing the Rust workspace, adding/removing crates, editing workspace dependencies, running cargo nextest/audit/deny, configuring Cargo profiles for Android cross-compilation, debugging Cargo.lock churn, migrating crate edition, or wiring Gradle to cargo via the ripdpi.android.rust-native plugin.
Use when modifying the diagnostics scan pipeline, ScanRequest/ScanReport types, ProbeTask families, ripdpi-monitor-engine / ripdpi-diagnostics-* crates, strategy-probe candidates, the diagnostics catalog (packs/profiles), wire-schema contracts between Rust and Kotlin, DIAGNOSTICS_ENGINE_SCHEMA_VERSION, golden contract tests, or adding a new probe type / profile. Triggers on diagnostics scans, strategy probes, automatic audit, dpi-detector profiles, or anything in core/diagnostics or native/rust/crates/ripdpi-monitor-*.
Android-specific Rust build, verification, and packaging — per-target 16 KiB page alignment, size-optimized release profile, ELF symbol allowlist, .so size budgets, NDK 29 specifics. Use when modifying .cargo/config.toml for Android targets, the workspace [profile.release] / [profile.android-jni] block, or when verifying a built .so before release.
Telemetry and observability discipline for the RIPDPI Android Rust stack — control-plane vs data-plane logging, bounded flume event queues, atomic counters, snapshot polling, readiness callbacks, and deterministic JSON contracts. Use when authoring or modifying telemetry emission code, the bounded event ring, the Kotlin-side telemetry consumer, or any per-packet logging.
Custom detekt rules, DI/privacy/suppression guardrails, detekt.yml configuration, and false-positive triage.
| name | tdd |
| description | Test-first workflow for features, bug fixes, refactors, and project-specific test patterns. |
This skill is RIGID. Follow every step exactly. Do not skip RED. Do not write implementation before a failing test exists.
Full test stack documentation: docs/testing.md. Do not duplicate it here -- read it when you need runner details, CI lanes, or fixture locations.
Repeat this cycle for every behavior change:
./gradlew staticAnalysis before considering the cycle complete.Never batch multiple behaviors into one cycle. One test, one behavior, one cycle.
# Single test method
./gradlew :core:engine:testDebugUnitTest --tests "ClassName.method name"
# Single test class
./gradlew :core:engine:testDebugUnitTest --tests "ClassName"
# Single module
./gradlew :core:engine:testDebugUnitTest
Replace :core:engine with the target module (:core:service, :core:data, :core:diagnostics).
# Single test
cargo nextest run --locked -p crate_name test_name
# Single crate
cargo nextest run --locked -p crate_name
# Full workspace
cargo nextest run --locked --workspace
Golden tests are read-only by default. If your change intentionally alters a contract:
# Bless all golden fixtures
bash scripts/tests/bless-telemetry-goldens.sh
# Manual single-suite bless
RIPDPI_BLESS_GOLDENS=1 ./gradlew :core:engine:testDebugUnitTest
RIPDPI_BLESS_GOLDENS=1 cargo test --locked -p crate_name
Always review blessed diffs before committing. Golden changes require explanation in the commit message.
All test doubles are hand-written Fakes in core/engine/src/test/kotlin/com/poyka/ripdpi/core/TestDoubles.kt. The project does not use MockK, Mockito, or any mocking library.
Pattern:
Fake + interface name (e.g., FakeRipDpiProxyRuntime)Fault injection uses FaultQueue<T> from core/engine-api/src/main/kotlin/com/poyka/ripdpi/core/testing/FaultModel.kt.
Key types:
FaultQueue<T> -- ordered queue of faults matched by target enumFaultSpec<T> -- target + outcome + scope + optional message/payloadFaultScope.ONE_SHOT -- fires once then is consumedFaultScope.PERSISTENT -- fires on every matching call until clearedFaultOutcome -- EXCEPTION, TIMEOUT, DROP, RESET, MALFORMED_PAYLOAD, BLANK_PAYLOAD, PANICUsage in tests:
val bindings = FakeRipDpiProxyBindings()
bindings.faults.enqueue(
FaultSpec(
target = ProxyBindingFaultTarget.START,
outcome = FaultOutcome.EXCEPTION,
message = "simulated native crash",
)
)
| What you test | Location | Runner |
|---|---|---|
| Kotlin business logic | core/*/src/test/ | ./gradlew :core:*:testDebugUnitTest |
| Rust native logic | native/rust/crates/*/tests/ | cargo nextest run --locked -p crate |
| JNI integration | app/src/androidTest/.../integration/ | connectedDebugAndroidTest |
| Network E2E | app/src/androidTest/.../e2e/ | connectedDebugAndroidTest |
| Rust network E2E | native/rust/crates/*/tests/ | bash scripts/ci/run-rust-network-e2e.sh |
For non-trivial features, use context isolation:
This prevents the "write test and implementation together" anti-pattern.
./gradlew staticAnalysis covers detekt, ktlint, and Android lint. It applies to test code too.TestDoubles.kt.FaultSpec + FaultQueue, not ad-hoc exception throwing.@Test fun proxy start propagates native exception().fn proxy_start_propagates_native_exception().| Mistake | Fix |
|---|---|
| Using MockK or Mockito | Write a Fake* class in TestDoubles.kt |
| Skipping the RED step | Run the test first. If it passes, your test is wrong. |
| Multiple assertions per cycle | Split into separate test methods, one behavior each |
runBlocking in coroutine tests | Use runTest from kotlinx-coroutines-test |
| Blessing goldens without review | Run git diff on fixture files before committing |
| Testing private internals | Test through the public API of the class under test |
| Putting helpers in test classes | Add shared helpers to TestDoubles.kt |
FaultScope.PERSISTENT when ONE_SHOT suffices | Default to ONE_SHOT; use PERSISTENT only for repeated-call scenarios |
For deeper coverage of anti-patterns, see references/testing-anti-patterns.md.