1 /*
2  * Copyright (c) 2025 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <atomic>
8 #include <cstdint>
9 #include <zephyr/ztest.h>
10 
11 namespace
12 {
13 std::atomic<uint8_t> atomic_u8;
14 std::atomic<uint16_t> atomic_u16;
15 std::atomic<uint32_t> atomic_u32;
16 } // namespace
17 
18 /**
19  * @brief This `before` function is run before each test in the suite.
20  *
21  * It ensures that all atomic variables are reset to a known state (0)
22  * so that the tests are independent and repeatable.
23  */
cxx_atomic_before(void * fixture)24 static void cxx_atomic_before(void *fixture)
25 {
26 	atomic_u8.store(0);
27 	atomic_u16.store(0);
28 	atomic_u32.store(0);
29 }
30 
31 /**
32  * @brief Tests the 1-byte (uint8_t) atomic implementation.
33  */
ZTEST(cxx_atomic,test_u8_compare_exchange_weak)34 ZTEST(cxx_atomic, test_u8_compare_exchange_weak)
35 {
36 	/* === Test 1: Successful exchange === */
37 	/* We expect the value to be 0, so this exchange should succeed. */
38 	uint8_t expected = 0;
39 	const uint8_t desired = 42;
40 
41 	/* Loop until the weak exchange succeeds. */
42 	while (!atomic_u8.compare_exchange_weak(expected, desired)) {
43 	}
44 	zassert_equal(atomic_u8.load(), desired, "Value should have been updated to 42");
45 
46 	/* === Test 2: Failed exchange === */
47 	/* Now, the atomic value is 42. We will set `expected` to 0, so the exchange must fail. */
48 	expected = 0;
49 	const uint8_t new_desired = 99;
50 	bool success = atomic_u8.compare_exchange_weak(expected, new_desired);
51 
52 	zassert_false(success, "Exchange should have failed");
53 	zassert_equal(atomic_u8.load(), desired, "Value should remain 42");
54 	/* Crucially, `expected` should be updated with the value that caused the failure. */
55 	zassert_equal(expected, desired, "Expected should be updated to 42");
56 }
57 
58 /**
59  * @brief Tests the 2-byte (uint16_t) atomic implementation.
60  */
ZTEST(cxx_atomic,test_u16_compare_exchange_weak)61 ZTEST(cxx_atomic, test_u16_compare_exchange_weak)
62 {
63 	/* === Test 1: Successful exchange === */
64 	uint16_t expected = 0;
65 	const uint16_t desired = 1337;
66 	while (!atomic_u16.compare_exchange_weak(expected, desired)) {
67 	}
68 	zassert_equal(atomic_u16.load(), desired, "Value should have been updated to 1337");
69 
70 	/* === Test 2: Failed exchange === */
71 	expected = 0;
72 	const uint16_t new_desired = 9999;
73 	bool success = atomic_u16.compare_exchange_weak(expected, new_desired);
74 
75 	zassert_false(success, "Exchange should have failed");
76 	zassert_equal(atomic_u16.load(), desired, "Value should remain 1337");
77 	zassert_equal(expected, desired, "Expected should be updated to 1337");
78 }
79 
80 /**
81  * @brief Tests the 4-byte (uint32_t) atomic implementation.
82  */
ZTEST(cxx_atomic,test_u32_compare_exchange_weak)83 ZTEST(cxx_atomic, test_u32_compare_exchange_weak)
84 {
85 	/* === Test 1: Successful exchange === */
86 	uint32_t expected = 0;
87 	const uint32_t desired = 0xDEADBEEF;
88 	while (!atomic_u32.compare_exchange_weak(expected, desired)) {
89 	}
90 	zassert_equal(atomic_u32.load(), desired, "Value should have been updated to 0xDEADBEEF");
91 
92 	/* === Test 2: Failed exchange === */
93 	expected = 0;
94 	const uint32_t new_desired = 0x12345678;
95 	bool success = atomic_u32.compare_exchange_weak(expected, new_desired);
96 
97 	zassert_false(success, "Exchange should have failed");
98 	zassert_equal(atomic_u32.load(), desired, "Value should remain 0xDEADBEEF");
99 	zassert_equal(expected, desired, "Expected should be updated to 0xDEADBEEF");
100 }
101 
102 ZTEST_SUITE(cxx_atomic, nullptr, nullptr, cxx_atomic_before, nullptr, nullptr);
103