/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/runtime/sync_test.nv
162 строки
5 KB
Evgeniy Golovin
style(std): D452 — migrate to canonical match-arm/statement separators
10 авг 2026, 03:57
10 авг 2026, 03:57
685589a
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // Plan 182 Ф.2 ([M-sync-test-stale-duplicate]) — honest beside-test for // std/runtime/sync.nv. The previous sync_test.nv was a stale PARTIAL COPY of // an old sync.nv snapshot (re-declaring MemOrdering/AtomicInt/AtomicBool/ // Mutex/WaitGroup instead of testing them) — it had no `test{}` blocks at // all and collided with sync.nv's own declarations (`duplicate top-level // name MemOrdering`) the moment both were compiled together. std/runtime // does not use the folder-shared-CU convention (each file here is its own // module, D29 rev-3 parent.X — confirmed by the checker's own // E_D78_MODULE_PATH_MISMATCH message), so this is a genuinely separate // module that imports std.runtime.sync explicitly, same shape as // std/time/units_test.nv importing std.time.duration. module runtime.sync_test import std.runtime.sync.{MemOrdering, fence, AtomicInt, AtomicBool, AtomicI64, AtomicI32, AtomicUint, Mutex, WaitGroup, Once, Semaphore} test "MemOrdering + fence: SeqCst fence is a no-op smoke" { fence(MemOrdering.SeqCst) fence(MemOrdering.Acquire) fence(MemOrdering.Release) fence(MemOrdering.Relaxed) assert(true) } test "AtomicInt: new/load/store/fetch_add/fetch_sub/compare_exchange" { mut c = AtomicInt.new(0) assert(c.load() == 0) c.store(10) assert(c.load() == 10) ro prev = c.fetch_add(5) assert(prev == 10) assert(c.load() == 15) ro prev2 = c.fetch_sub(3) assert(prev2 == 15) assert(c.load() == 12) assert(c.compare_exchange(12, 100).is_ok()) assert(c.load() == 100) assert(c.compare_exchange(12, 200).is_err()) assert(c.load() == 100) } test "AtomicBool: new/load/store/compare_exchange/swap" { mut f = AtomicBool.new(false) assert(!f.load()) f.store(true) assert(f.load()) assert(f.compare_exchange(true, false).is_ok()) assert(!f.load()) ro prev = f.swap(true) assert(!prev) assert(f.load()) } test "Plan 207 [M-cas-return-witnessed-value]: compare_exchange carries the witness on Err" { // Strong CAS: success -> Ok(()); failure -> Err(actual) with the real // current value (no extra load() needed to retry). mut c = AtomicI64.new(10) match c.compare_exchange(10, 20) { Ok(_) => assert(true) Err(_) => assert(false) } assert(c.load() == 20) match c.compare_exchange(999, 30) { Ok(_) => assert(false) Err(actual) => assert(actual == 20) // witness == real current value } assert(c.load() == 20) // failed CAS must not have mutated the atomic // Explicit-ordering overload builds the same Result shape. mut c32 = AtomicI32.new(5) match c32.compare_exchange(5, 6, success: MemOrdering.SeqCst, failure: MemOrdering.SeqCst) { Ok(_) => assert(true) Err(_) => assert(false) } match c32.compare_exchange(0, 7, success: MemOrdering.SeqCst, failure: MemOrdering.SeqCst) { Ok(_) => assert(false) Err(actual) => assert(actual == 6) } // compare_exchange_weak: witness is correct even though it may // spuriously report failure on some architectures. mut b = AtomicBool.new(false) match b.compare_exchange_weak(false, true) { Ok(_) => assert(b.load()) Err(actual) => assert(actual == false) } // Retry-loop idiom (the motivating use case from the plan): rebuild // `cur` from the witness instead of calling load() again. mut n = AtomicUint.new(1) mut cur = n.load() mut iterations = 0 loop { iterations += 1 assert(iterations < 100) // guard against infinite loop on a bug ro next = cur * 2 match n.compare_exchange(cur, next) { Ok(_) => break Err(actual) => { cur = actual } } } assert(n.load() == 2) assert(cur == 1) } test "Mutex: lock/unlock guard + with_lock" { mut mu = Mutex.new() assert(!mu.is_locked()) consume guard = mu.lock() assert(mu.is_locked()) guard.unlock() assert(!mu.is_locked()) assert(mu.try_lock()) assert(mu.is_locked()) mu.unlock() ro doubled = mu.with_lock(|| 21 * 2) assert(doubled == 42) } test "WaitGroup: add/done/wait with a zero-remaining count returns immediately" { mut wg = WaitGroup.new() wg.add(2) wg.done() wg.done() wg.wait() // counter is 0 — must not park assert(true) } test "Once: call_once runs exactly once" { mut once = Once.new() mut count = AtomicInt.new(0) assert(!once.is_completed()) once.call_once(|| { count.fetch_add(1) }) once.call_once(|| { count.fetch_add(1) }) assert(once.is_completed()) assert(count.load() == 1) } test "Semaphore: try_acquire guard — Some/None + auto-release on scope exit" { mut sem = Semaphore.new(1) { consume p = match sem.try_acquire() { Some(consume p) => p None => { assert(false); return } } assert(sem.available_permits() == 0) match sem.try_acquire() { Some(consume p2) => { assert(false); p2.release() } None => {} } } assert(sem.available_permits() == 1) match sem.try_acquire() { Some(consume p3) => p3.release() None => assert(false) } assert(sem.available_permits() == 1) }