Branch data Line data Source code
1 : : #include "test_libmem_all.h"
2 : :
3 : : /**
4 : : * @brief Verify m_resize behavior with flag combinations on typed point descriptors
5 : : *
6 : : * Drives two descriptors over a user-defined point element type
7 : : * (struct with two int fields, see test_libmem_utils.h) through a
8 : : * chain of m_resize calls covering the practically interesting flag
9 : : * combinations. The plain descriptor exercises an unflagged grow.
10 : : * The second descriptor is taken through a fresh grow with
11 : : * ZERO_NEW_MEMORY, then through a deterministic combined-flag grow:
12 : : * the test exposes a tail, writes non-zero typed elements into it,
13 : : * hides it again without releasing storage, and grows with
14 : : * ZERO_NEW_MEMORY | RELEASE_UNUSED. That grow has to preserve the
15 : : * existing payload while clearing every re-exposed tail element. A
16 : : * shrink with the same combined flags then has to keep the surviving
17 : : * payload intact. Both read-only and writable views are exercised:
18 : : * m_data_ro confirms the zero fill through the typed element layout,
19 : : * and m_data prepares the non-zero payload that resize must clear or
20 : : * preserve as appropriate.
21 : : * The final block asserts that both descriptors stayed in data mode
22 : : * (is_string == false, string_length == 0) for the whole sequence
23 : : * and that m_del releases each cleanly
24 : : *
25 : : * The test guards against two classes of regressions: confusion
26 : : * between byte size and logical element size in resize bookkeeping
27 : : * (checking both .x and .y makes the assertion depend on the full
28 : : * point element, not only its first field), and silent loss of
29 : : * existing payload across grow/shrink with combined flags
30 : : *
31 : : * @return Return describing success or failure
32 : : */
33 : 1 : Return test_libmem_0010(void)
34 : : {
35 : 1 : INITTEST;
36 : :
37 : : /* Two typed descriptors over the user-defined point element so resize bookkeeping is exercised on a non-byte payload */
38 : 1 : m_create(point,points);
39 : 1 : m_create(point,zeroed_points);
40 : :
41 : : /* Both descriptors must enter the test in data mode with zero cached string length */
42 : 1 : ASSERT(points->string_length == 0);
43 : 1 : ASSERT(points->is_string == false);
44 : 1 : ASSERT(zeroed_points->string_length == 0);
45 : 1 : ASSERT(zeroed_points->is_string == false);
46 : :
47 : : /* Exercise an ordinary typed grow and a successful fresh grow with ZERO_NEW_MEMORY */
48 : 1 : ASSERT(SUCCESS == m_resize(points,5));
49 : 1 : ASSERT(SUCCESS == m_resize(zeroed_points,3,ZERO_NEW_MEMORY));
50 : :
51 : : /* Writable view receives a non-zero surviving payload that later resize calls must preserve */
52 : 1 : point *zeroed_writer = m_data(point,zeroed_points);
53 : 1 : ASSERT(zeroed_writer != NULL);
54 : :
55 : 1 : IF(zeroed_writer != NULL)
56 : : {
57 : 1 : zeroed_writer[0] = (point){1,1};
58 : : }
59 : :
60 : : /* Expose and dirty the future tail before hiding it inside the retained allocation */
61 : 1 : ASSERT(SUCCESS == m_resize(zeroed_points,6));
62 : :
63 : 1 : zeroed_writer = m_data(point,zeroed_points);
64 : 1 : ASSERT(zeroed_writer != NULL);
65 : :
66 : 1 : IF(zeroed_writer != NULL)
67 : : {
68 : 1 : zeroed_writer[3] = (point){31,32};
69 : 1 : zeroed_writer[4] = (point){41,42};
70 : 1 : zeroed_writer[5] = (point){51,52};
71 : : }
72 : :
73 : 1 : ASSERT(SUCCESS == m_resize(zeroed_points,3));
74 : :
75 : : /* Grow with the combined flags must preserve the prefix and clear the retained non-zero tail */
76 : 1 : ASSERT(SUCCESS == m_resize(zeroed_points,6,ZERO_NEW_MEMORY | RELEASE_UNUSED));
77 : :
78 : : /* Index 0 remains (1,1), while every re-exposed tail point must be all-zero */
79 : 1 : const point *expanded_view = m_data_ro(point,zeroed_points);
80 : 1 : ASSERT(expanded_view != NULL);
81 : :
82 : 1 : IF(expanded_view != NULL)
83 : : {
84 : 1 : ASSERT(expanded_view[0].x == 1);
85 : 1 : ASSERT(expanded_view[0].y == 1);
86 : 1 : ASSERT(expanded_view[3].x == 0);
87 : 1 : ASSERT(expanded_view[3].y == 0);
88 : 1 : ASSERT(expanded_view[4].x == 0);
89 : 1 : ASSERT(expanded_view[4].y == 0);
90 : 1 : ASSERT(expanded_view[5].x == 0);
91 : 1 : ASSERT(expanded_view[5].y == 0);
92 : : }
93 : :
94 : : /* Shrink with the same flag combination has to keep the previously written surviving element intact */
95 : 1 : ASSERT(SUCCESS == m_resize(zeroed_points,2,ZERO_NEW_MEMORY | RELEASE_UNUSED));
96 : :
97 : : /* Logical length now matches the requested two and the surviving element still reads (1,1) */
98 : 1 : const point *shrunk_view = m_data_ro(point,zeroed_points);
99 : 1 : ASSERT(shrunk_view != NULL);
100 : :
101 : 1 : IF(shrunk_view != NULL)
102 : : {
103 : 1 : ASSERT(zeroed_points->length == 2);
104 : 1 : ASSERT(shrunk_view[0].x == 1);
105 : 1 : ASSERT(shrunk_view[0].y == 1);
106 : : }
107 : :
108 : : /* Mode invariants survived the full resize chain and m_del releases both descriptors cleanly */
109 : 1 : ASSERT(points->string_length == 0);
110 : 1 : ASSERT(points->is_string == false);
111 : 1 : ASSERT(zeroed_points->string_length == 0);
112 : 1 : ASSERT(zeroed_points->is_string == false);
113 : 1 : call(m_del(points));
114 : 1 : call(m_del(zeroed_points));
115 : :
116 : 1 : RETURN_STATUS;
117 : : }
|