├── .github └── workflows │ └── scv-ci-workflow.yaml ├── .gitignore ├── CMakeLists.txt ├── Doxyfile ├── LICENSE ├── README.md ├── scv.c ├── scv.h └── test ├── greatest.h └── test_scv.c /.github/workflows/scv-ci-workflow.yaml: -------------------------------------------------------------------------------- 1 | name: scv CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | windows: 7 | name: Windows ${{ matrix.config.name }} 8 | runs-on: windows-2022 9 | 10 | strategy: 11 | matrix: 12 | config: 13 | - name: MSVC x64 14 | generator: Visual Studio 17 2022 15 | cmake-flags: -A x64 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Configure 21 | run: cmake -G "${{ matrix.config.generator }}" ${{ matrix.config.cmake-flags }} -B build 22 | 23 | - name: Build 24 | run: cd build && cmake --build . --config Debug 25 | 26 | - name: Test 27 | run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 -C Debug 28 | 29 | linux: 30 | name: Linux ${{ matrix.config.name }} 31 | runs-on: ubuntu-latest 32 | env: 33 | CC: ${{ matrix.config.cc }} 34 | 35 | strategy: 36 | matrix: 37 | config: 38 | - name: Clang UBSan 39 | cc: clang 40 | cmake-flags: -DCMAKE_C_FLAGS_DEBUG='-g -fsanitize=undefined' 41 | 42 | - name: Clang ASan 43 | cc: clang 44 | cmake-flags: -DCMAKE_C_FLAGS_DEBUG='-O1 -g -fsanitize=address -fno-omit-frame-pointer' 45 | 46 | steps: 47 | - uses: actions/checkout@v4 48 | 49 | - name: Configure 50 | run: cmake ${{ matrix.config.cmake-flags }} -DCMAKE_BUILD_TYPE=Debug -B build 51 | 52 | - name: Build 53 | run: cd build && cmake --build . --verbose 54 | 55 | - name: Test 56 | run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 57 | 58 | coverage: 59 | name: Linux Coverage 60 | runs-on: ubuntu-latest 61 | 62 | steps: 63 | - uses: actions/checkout@v4 64 | 65 | - name: Configure 66 | run: cmake -DCMAKE_C_FLAGS_DEBUG='-g -O0 --coverage' -DCMAKE_BUILD_TYPE=Debug -B build 67 | 68 | - name: Build 69 | run: cd build && cmake --build . --verbose 70 | 71 | - name: Test 72 | run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 73 | 74 | - name: Generate coverage 75 | run: cd build && gcov -b CMakeFiles/scv.dir/scv.c.gcno -o CMakeFiles/scv.dir 76 | 77 | - name: Upload coverage to Codecov 78 | uses: codecov/codecov-action@v3 79 | with: 80 | files: ./build/scv.c.gcov 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.obj 3 | 4 | *.a 5 | *.lib 6 | 7 | *.so 8 | *.so.* 9 | *.dll 10 | 11 | *.exe 12 | 13 | /build/ 14 | /doc/ 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(scv C) 4 | 5 | include(CTest) 6 | 7 | if(MSVC) 8 | add_compile_options(/W3) 9 | elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") 10 | add_compile_options(-Wall -Wextra -pedantic) 11 | endif() 12 | 13 | add_library(scv scv.c scv.h) 14 | target_include_directories(scv PUBLIC $) 15 | 16 | if(BUILD_TESTING) 17 | add_executable(test_scv test/test_scv.c) 18 | target_link_libraries(test_scv PRIVATE scv) 19 | if(MSVC) 20 | target_compile_definitions(test_scv PRIVATE _CRT_SECURE_NO_WARNINGS) 21 | endif() 22 | 23 | add_test(test_scv test_scv) 24 | endif() 25 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.8.6 2 | PROJECT_NAME = "Simple C Vector" 3 | OUTPUT_DIRECTORY = doc 4 | JAVADOC_AUTOBRIEF = YES 5 | TAB_SIZE = 8 6 | OPTIMIZE_OUTPUT_FOR_C = YES 7 | EXTRACT_ALL = YES 8 | INPUT = scv.h README.md 9 | GENERATE_LATEX = NO 10 | USE_MDFILE_AS_MAINPAGE = README.md 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Simple C Vector 3 | =============== 4 | 5 | Copyright 2003-2014 Joergen Ibsen 6 | 7 | 8 | 9 | [![scv CI](https://github.com/jibsen/scv/actions/workflows/scv-ci-workflow.yaml/badge.svg)](https://github.com/jibsen/scv/actions) [![codecov](https://codecov.io/gh/jibsen/scv/branch/master/graph/badge.svg)](https://codecov.io/gh/jibsen/scv) 10 | 11 | About 12 | ----- 13 | 14 | Simple C Vector (scv) is an ANSI C implementation of a [dynamic array][dyna], 15 | with an interface similar to C++ [std::vector][vector]. 16 | 17 | I wrote it for a project years ago, and decided to dust it off and make it 18 | available under the [Apache License](LICENSE). 19 | 20 | [dyna]: http://en.wikipedia.org/wiki/Dynamic_array 21 | [vector]: http://en.cppreference.com/w/cpp/container/vector 22 | 23 | 24 | Usage 25 | ----- 26 | 27 | The include file `scv.h` contains documentation in the form of [doxygen][] 28 | comments. A configuration file is included, run `doxygen` to generate 29 | documentation in HTML format. 30 | 31 | You can add the source files `scv.c` and `scv.h` to your own projects. 32 | 33 | For CI, scv uses [CMake][] to provide an easy way to build and test across 34 | various platforms and toolsets. To create a build system for the tools on 35 | your platform, and build scv, use something along the lines of: 36 | 37 | ~~~sh 38 | mkdir build 39 | cd build 40 | cmake .. 41 | cmake --build . 42 | ~~~ 43 | 44 | [doxygen]: http://www.doxygen.org/ 45 | [CMake]: http://www.cmake.org/ 46 | 47 | 48 | Example 49 | ------- 50 | 51 | Here is an example that reads integer coordinates in the form `x,y` 52 | into a `scv_vector` and prints them in lexicographical order: 53 | 54 | ~~~c 55 | #include 56 | #include 57 | 58 | #include "scv.h" 59 | 60 | struct point { 61 | int x; 62 | int y; 63 | }; 64 | 65 | int point_compare(const struct point *lhs, const struct point *rhs) 66 | { 67 | if (lhs->x == rhs->x) { 68 | return lhs->y - rhs->y; 69 | } 70 | 71 | return lhs->x - rhs->x; 72 | } 73 | 74 | int main(void) 75 | { 76 | struct scv_vector *v; 77 | struct point p; 78 | size_t i; 79 | 80 | /* create a scv_vector of points, reserving space for 10 */ 81 | v = scv_new(sizeof p, 10); 82 | 83 | /* read coordinates into p and append to v */ 84 | while (scanf("%d,%d", &p.x, &p.y) == 2) { 85 | scv_push_back(v, &p); 86 | } 87 | 88 | /* sort points in v */ 89 | qsort(scv_data(v), scv_size(v), scv_objsize(v), point_compare); 90 | 91 | /* print points */ 92 | for (i = 0; i < scv_size(v); ++i) { 93 | struct point *pp = scv_at(v, i); 94 | 95 | printf("%d,%d\n", pp->x, pp->y); 96 | } 97 | 98 | scv_delete(v); 99 | 100 | return 0; 101 | } 102 | ~~~ 103 | 104 | 105 | Details 106 | ------- 107 | 108 | The user is responsible for passing pointers to valid `scv_vector` structures. 109 | The code contains assertions to help while debugging. 110 | 111 | To enable the code to work in general, independent of the type of objects 112 | stored in a particular `scv_vector`, functions for inserting and accessing 113 | elements take and return `void` pointers. 114 | 115 | This has the drawback that you cannot use a constant expression directly, but 116 | need an actual object that you can pass a pointer to, when calling functions 117 | like `scv_push_back()`. 118 | 119 | Pointers into the memory used to hold the elements of a `scv_vector`, will be 120 | valid until a function causes a reallocation. If you know the element type, 121 | and speed is important, you can use pointers to access the elements directly: 122 | 123 | ~~~c 124 | /* v is a scv_vector of int, get a pointer to it's data */ 125 | int *p = scv_data(v); 126 | 127 | /* we can access the elements of v using p */ 128 | p[5] = 42; 129 | ~~~ 130 | 131 | scv uses `malloc()` for memory allocation, which works well in many cases, 132 | but if needed, you could improve performance by using a custom allocator. 133 | -------------------------------------------------------------------------------- /scv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * scv - Simple C Vector 3 | * 4 | * scv.c 5 | * 6 | * Copyright 2003-2014 Joergen Ibsen 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * SPDX-License-Identifier: Apache-2.0 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "scv.h" 28 | 29 | /** 30 | * Return a pointer to element number `i` of `v`, without error checking. 31 | * 32 | * @param v pointer to `scv_vector` 33 | * @param i index 34 | * @return pointer to element `i` 35 | */ 36 | #define SCV_AT(v, i) ((void *) ((char *) (v)->data + (i) * (v)->objsize)) 37 | 38 | /** 39 | * Minimum allocation size in bytes. 40 | */ 41 | #define SCV_MIN_ALLOC (64u) 42 | 43 | /** 44 | * Grow the capacity of `v` to at least `capacity`. 45 | * 46 | * If more space is needed, grow `v` to `capacity`, but at least by a factor 47 | * of 1.5. 48 | * 49 | * @param v pointer to `scv_vector` 50 | * @param capacity requested capacity 51 | * @return zero on success, error code on error 52 | */ 53 | static int scv_i_grow(struct scv_vector *v, size_t capacity) 54 | { 55 | void *newdata; 56 | size_t newcapacity; 57 | 58 | assert(v != NULL); 59 | assert(v->data != NULL); 60 | 61 | if (capacity <= v->capacity) { 62 | return SCV_OK; 63 | } 64 | 65 | assert(v->objsize > 0); 66 | 67 | if (capacity >= (size_t) -1 / v->objsize) { 68 | return SCV_ERANGE; 69 | } 70 | 71 | /* Growth factor 2 for small vectors, 1.5 for larger */ 72 | if (v->capacity < 4096 / v->objsize) { 73 | newcapacity = v->capacity + v->capacity + 1; 74 | } 75 | else { 76 | newcapacity = v->capacity + v->capacity / 2 + 1; 77 | } 78 | 79 | if (capacity > newcapacity || newcapacity >= (size_t) -1 / v->objsize) { 80 | newcapacity = capacity; 81 | } 82 | 83 | newdata = realloc(v->data, newcapacity * v->objsize); 84 | 85 | if (newdata == NULL) { 86 | return SCV_ENOMEM; 87 | } 88 | 89 | v->data = newdata; 90 | v->capacity = newcapacity; 91 | 92 | return SCV_OK; 93 | } 94 | 95 | struct scv_vector *scv_new(size_t objsize, size_t capacity) 96 | { 97 | struct scv_vector *v; 98 | 99 | if (capacity == 0) { 100 | capacity = 1; 101 | } 102 | 103 | if (objsize == 0 || capacity >= (size_t) -1 / objsize) { 104 | return NULL; 105 | } 106 | 107 | v = (struct scv_vector *) malloc(sizeof *v); 108 | 109 | if (v == NULL) { 110 | return NULL; 111 | } 112 | 113 | /* Minimum capacity is SCV_MIN_ALLOC bytes or 1 element */ 114 | if (capacity * objsize < SCV_MIN_ALLOC) { 115 | capacity = (SCV_MIN_ALLOC + (objsize - 1)) / objsize; 116 | } 117 | 118 | v->data = malloc(capacity * objsize); 119 | 120 | if (v->data == NULL) { 121 | free(v); 122 | return NULL; 123 | } 124 | 125 | v->objsize = objsize; 126 | v->size = 0; 127 | v->capacity = capacity; 128 | 129 | return v; 130 | } 131 | 132 | void scv_delete(struct scv_vector *v) 133 | { 134 | if (v == NULL) { 135 | return; 136 | } 137 | 138 | if (v->data != NULL) { 139 | free(v->data); 140 | v->data = NULL; 141 | } 142 | 143 | v->objsize = 0; 144 | v->size = 0; 145 | v->capacity = 0; 146 | 147 | free(v); 148 | } 149 | 150 | void *scv_at(struct scv_vector *v, size_t i) 151 | { 152 | assert(v != NULL); 153 | assert(v->data != NULL); 154 | 155 | if (i >= v->size) { 156 | return NULL; 157 | } 158 | 159 | return SCV_AT(v, i); 160 | } 161 | 162 | void *scv_front(struct scv_vector *v) 163 | { 164 | assert(v != NULL); 165 | assert(v->data != NULL); 166 | 167 | if (v->size == 0) { 168 | return NULL; 169 | } 170 | 171 | return v->data; 172 | } 173 | 174 | void *scv_back(struct scv_vector *v) 175 | { 176 | assert(v != NULL); 177 | assert(v->data != NULL); 178 | 179 | if (v->size == 0) { 180 | return NULL; 181 | } 182 | 183 | return SCV_AT(v, v->size - 1); 184 | } 185 | 186 | void *scv_data(struct scv_vector *v) 187 | { 188 | assert(v != NULL); 189 | assert(v->data != NULL); 190 | 191 | if (v->size == 0) { 192 | return NULL; 193 | } 194 | 195 | return v->data; 196 | } 197 | 198 | int scv_empty(const struct scv_vector *v) 199 | { 200 | assert(v != NULL); 201 | assert(v->data != NULL); 202 | 203 | return v->size == 0; 204 | } 205 | 206 | size_t scv_size(const struct scv_vector *v) 207 | { 208 | assert(v != NULL); 209 | assert(v->data != NULL); 210 | 211 | return v->size; 212 | } 213 | 214 | size_t scv_objsize(const struct scv_vector *v) 215 | { 216 | assert(v != NULL); 217 | assert(v->data != NULL); 218 | 219 | return v->objsize; 220 | } 221 | 222 | int scv_reserve(struct scv_vector *v, size_t capacity) 223 | { 224 | void *newdata; 225 | 226 | assert(v != NULL); 227 | assert(v->data != NULL); 228 | 229 | if (capacity <= v->capacity) { 230 | return SCV_OK; 231 | } 232 | 233 | assert(v->objsize > 0); 234 | 235 | if (capacity >= (size_t) -1 / v->objsize) { 236 | return SCV_ERANGE; 237 | } 238 | 239 | newdata = realloc(v->data, capacity * v->objsize); 240 | 241 | if (newdata == NULL) { 242 | return SCV_ENOMEM; 243 | } 244 | 245 | v->data = newdata; 246 | v->capacity = capacity; 247 | 248 | return SCV_OK; 249 | } 250 | 251 | size_t scv_capacity(const struct scv_vector *v) 252 | { 253 | assert(v != NULL); 254 | assert(v->data != NULL); 255 | 256 | return v->capacity; 257 | } 258 | 259 | int scv_shrink_to_fit(struct scv_vector *v) 260 | { 261 | void *newdata; 262 | size_t newcapacity; 263 | 264 | assert(v != NULL); 265 | assert(v->data != NULL); 266 | 267 | if (v->capacity == v->size) { 268 | return SCV_OK; 269 | } 270 | 271 | newcapacity = v->size; 272 | 273 | assert(v->objsize > 0); 274 | assert(newcapacity < (size_t) -1 / v->objsize); 275 | 276 | /* Minimum capacity is SCV_MIN_ALLOC bytes or 1 element */ 277 | if (newcapacity * v->objsize < SCV_MIN_ALLOC) { 278 | newcapacity = (SCV_MIN_ALLOC + (v->objsize - 1)) / v->objsize; 279 | } 280 | 281 | newdata = realloc(v->data, newcapacity * v->objsize); 282 | 283 | if (newdata == NULL) { 284 | return SCV_ENOMEM; 285 | } 286 | 287 | v->data = newdata; 288 | v->capacity = newcapacity; 289 | 290 | return SCV_OK; 291 | } 292 | 293 | int scv_clear(struct scv_vector *v) 294 | { 295 | assert(v != NULL); 296 | assert(v->data != NULL); 297 | 298 | v->size = 0; 299 | 300 | return SCV_OK; 301 | } 302 | 303 | int scv_assign(struct scv_vector *v, const void *data, size_t nobj) 304 | { 305 | assert(v != NULL); 306 | assert(v->data != NULL); 307 | 308 | assert(v->objsize > 0); 309 | 310 | if (nobj >= (size_t) -1 / v->objsize) { 311 | return SCV_ERANGE; 312 | } 313 | 314 | if (nobj > v->capacity) { 315 | int res = scv_i_grow(v, nobj); 316 | 317 | if (res != SCV_OK) { 318 | return res; 319 | } 320 | } 321 | 322 | if (data != NULL && nobj > 0) { 323 | memcpy(v->data, data, nobj * v->objsize); 324 | } 325 | 326 | v->size = nobj; 327 | 328 | return SCV_OK; 329 | } 330 | 331 | int scv_replace(struct scv_vector *v, size_t i, size_t j, const void *data, size_t nobj) 332 | { 333 | assert(v != NULL); 334 | assert(v->data != NULL); 335 | 336 | if (i > j || j > v->size) { 337 | return SCV_ERANGE; 338 | } 339 | 340 | assert(v->objsize > 0); 341 | 342 | if (nobj >= (size_t) -1 / v->objsize - (v->size - (j - i))) { 343 | return SCV_ERANGE; 344 | } 345 | 346 | if (v->size - (j - i) + nobj > v->capacity) { 347 | int res = scv_i_grow(v, v->size - (j - i) + nobj); 348 | 349 | if (res != SCV_OK) { 350 | return res; 351 | } 352 | } 353 | 354 | if (j < v->size && i + nobj != j) { 355 | memmove(SCV_AT(v, i + nobj), SCV_AT(v, j), (v->size - j) * v->objsize); 356 | } 357 | 358 | if (data != NULL && nobj > 0) { 359 | memcpy(SCV_AT(v, i), data, nobj * v->objsize); 360 | } 361 | 362 | v->size = v->size - (j - i) + nobj; 363 | 364 | return SCV_OK; 365 | } 366 | 367 | int scv_insert(struct scv_vector *v, size_t i, const void *data, size_t nobj) 368 | { 369 | return scv_replace(v, i, i, data, nobj); 370 | } 371 | 372 | int scv_erase(struct scv_vector *v, size_t i, size_t j) 373 | { 374 | return scv_replace(v, i, j, NULL, 0); 375 | } 376 | 377 | int scv_push_back(struct scv_vector *v, const void *data) 378 | { 379 | assert(v != NULL); 380 | assert(v->data != NULL); 381 | 382 | if (v->size + 1 > v->capacity) { 383 | int res = scv_i_grow(v, v->size + 1); 384 | 385 | if (res != SCV_OK) { 386 | return res; 387 | } 388 | } 389 | 390 | assert(v->objsize > 0); 391 | 392 | if (data != NULL) { 393 | memcpy(SCV_AT(v, v->size), data, v->objsize); 394 | } 395 | 396 | v->size += 1; 397 | 398 | return SCV_OK; 399 | } 400 | 401 | int scv_pop_back(struct scv_vector *v) 402 | { 403 | assert(v != NULL); 404 | assert(v->data != NULL); 405 | 406 | if (v->size == 0) { 407 | return SCV_ERANGE; 408 | } 409 | 410 | v->size -= 1; 411 | 412 | return SCV_OK; 413 | } 414 | 415 | int scv_resize(struct scv_vector *v, size_t size) 416 | { 417 | assert(v != NULL); 418 | assert(v->data != NULL); 419 | 420 | assert(v->objsize > 0); 421 | 422 | if (size >= (size_t) -1 / v->objsize) { 423 | return SCV_ERANGE; 424 | } 425 | 426 | if (size > v->capacity) { 427 | int res = scv_i_grow(v, size); 428 | 429 | if (res != SCV_OK) { 430 | return res; 431 | } 432 | } 433 | 434 | v->size = size; 435 | 436 | return SCV_OK; 437 | } 438 | 439 | int scv_copy(struct scv_vector *dst, const struct scv_vector *src) 440 | { 441 | assert(dst != NULL); 442 | assert(dst->data != NULL); 443 | assert(src != NULL); 444 | assert(src->data != NULL); 445 | 446 | if (dst == src || dst->objsize != src->objsize) { 447 | return SCV_EINVAL; 448 | } 449 | 450 | return scv_assign(dst, src->data, src->size); 451 | } 452 | 453 | int scv_swap(struct scv_vector *scv1, struct scv_vector *scv2) 454 | { 455 | struct scv_vector tmp; 456 | 457 | assert(scv1 != NULL); 458 | assert(scv2 != NULL); 459 | 460 | tmp = *scv1; 461 | *scv1 = *scv2; 462 | *scv2 = tmp; 463 | 464 | return SCV_OK; 465 | } 466 | -------------------------------------------------------------------------------- /scv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * scv - Simple C Vector 3 | * 4 | * scv.h 5 | * 6 | * Copyright 2003-2014 Joergen Ibsen 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * SPDX-License-Identifier: Apache-2.0 21 | */ 22 | 23 | #ifndef SCV_H_INCLUDED 24 | #define SCV_H_INCLUDED 25 | 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /** 33 | * Structure representing a `scv_vector`. 34 | * 35 | * @see scv_new 36 | */ 37 | struct scv_vector { 38 | void *data; /**< Pointer to the underlying memory. */ 39 | size_t objsize; /**< Size of each element in bytes. */ 40 | size_t size; /**< Used size in number of elements. */ 41 | size_t capacity; /**< Capacity in number of elements. */ 42 | }; 43 | 44 | /** 45 | * Status codes returned by some functions. 46 | */ 47 | typedef enum { 48 | SCV_OK = 0, /**< Success. */ 49 | SCV_ERROR = -1, /**< Generic error. */ 50 | SCV_ENOMEM = -2, /**< Out of memory. */ 51 | SCV_ERANGE = -3, /**< Overflow or out of range. */ 52 | SCV_EINVAL = -4 /**< Invalid argument. */ 53 | } scv_error_code; 54 | 55 | /** 56 | * Create a new `scv_vector`. 57 | * 58 | * `capacity` is in number of elements. 59 | * 60 | * @param objsize size of each element in bytes 61 | * @param capacity initial capacity in number of elements 62 | * @return pointer to `scv_vector`, `NULL` on error 63 | */ 64 | struct scv_vector *scv_new(size_t objsize, size_t capacity); 65 | 66 | /** 67 | * Destroy `v`, freeing the associated memory. 68 | * 69 | * @param v pointer to `scv_vector`. 70 | */ 71 | void scv_delete(struct scv_vector *v); 72 | 73 | /** 74 | * Return a pointer to element number `i` of `v`. 75 | * 76 | * @param v pointer to `scv_vector` 77 | * @param i index 78 | * @return pointer to element `i`, `NULL` on error 79 | */ 80 | void *scv_at(struct scv_vector *v, size_t i); 81 | 82 | /** 83 | * Return a pointer to the first element of `v`. 84 | * 85 | * @param v pointer to `scv_vector` 86 | * @return pointer to first element, `NULL` on error 87 | */ 88 | void *scv_front(struct scv_vector *v); 89 | 90 | /** 91 | * Return a pointer to the last element of `v`. 92 | * 93 | * @param v pointer to `scv_vector` 94 | * @return pointer to last element, `NULL` on error 95 | */ 96 | void *scv_back(struct scv_vector *v); 97 | 98 | /** 99 | * Return a pointer to the elements of `v`. 100 | * 101 | * @param v pointer to `scv_vector` 102 | * @return pointer to elements, `NULL` if empty 103 | */ 104 | void *scv_data(struct scv_vector *v); 105 | 106 | /** 107 | * Check if `v` is empty. 108 | * 109 | * @param v pointer to `scv_vector` 110 | * @return non-zero if empty 111 | */ 112 | int scv_empty(const struct scv_vector *v); 113 | 114 | /** 115 | * Return the size of `v`. 116 | * 117 | * @param v pointer to `scv_vector` 118 | * @return size in number of elements 119 | */ 120 | size_t scv_size(const struct scv_vector *v); 121 | 122 | /** 123 | * Return the size of each element in `v`. 124 | * 125 | * @param v pointer to `scv_vector` 126 | * @return size of each element in bytes 127 | */ 128 | size_t scv_objsize(const struct scv_vector *v); 129 | 130 | /** 131 | * Reserve space in `v`. 132 | * 133 | * @param v pointer to `scv_vector` 134 | * @param capacity requested capacity 135 | * @return zero on success, error code on error 136 | */ 137 | int scv_reserve(struct scv_vector *v, size_t capacity); 138 | 139 | /** 140 | * Return the capacity of `v`. 141 | * 142 | * @param v pointer to `scv_vector` 143 | * @return capacity in number of elements 144 | */ 145 | size_t scv_capacity(const struct scv_vector *v); 146 | 147 | /** 148 | * Trim the capacity of `v` to the number of elements used. 149 | * 150 | * @param v pointer to `scv_vector` 151 | * @return zero on success, error code on error 152 | */ 153 | int scv_shrink_to_fit(struct scv_vector *v); 154 | 155 | /** 156 | * Remove all elements from `v`. 157 | * 158 | * @param v pointer to `scv_vector` 159 | * @return zero on success, error code on error 160 | */ 161 | int scv_clear(struct scv_vector *v); 162 | 163 | /** 164 | * Replace the contents of `v` with `nobj` elements from `data`. 165 | * 166 | * If `data` is `NULL`, any assigned elements are not initialized. 167 | * 168 | * `data` must not point inside `v`. 169 | * 170 | * @param v pointer to `scv_vector` 171 | * @param data pointer to data to copy into assigned elements 172 | * @param nobj number of elements to assign 173 | * @return zero on success, error code on error 174 | */ 175 | int scv_assign(struct scv_vector *v, const void *data, size_t nobj); 176 | 177 | /** 178 | * Replace elements from `i` up to, but not including, `j` in `v`, with 179 | * `nobj` elements from `data`. 180 | * 181 | * If `data` is `NULL`, any inserted elements are not initialized. 182 | * 183 | * `i` can be `scv_size(v)`, in which case elements are added at the end. 184 | * 185 | * `data` must not point inside `v`. 186 | * 187 | * @param v pointer to `scv_vector` 188 | * @param i start index 189 | * @param j end index 190 | * @param data pointer to data to copy into new elements 191 | * @param nobj number of elements to insert 192 | * @return zero on success, error code on error 193 | */ 194 | int scv_replace(struct scv_vector *v, size_t i, size_t j, const void *data, size_t nobj); 195 | 196 | /** 197 | * Insert `nobj` elements from `data` before element number `i` of `v`. 198 | * 199 | * If `data` is `NULL`, inserted elements are not initialized. 200 | * 201 | * `i` can be `scv_size(v)`, in which case elements are added at the end. 202 | * 203 | * `data` must not point inside `v`. 204 | * 205 | * @param v pointer to `scv_vector` 206 | * @param i index 207 | * @param data pointer to data to copy into new elements 208 | * @param nobj number of elements to insert 209 | * @return zero on success, error code on error 210 | */ 211 | int scv_insert(struct scv_vector *v, size_t i, const void *data, size_t nobj); 212 | 213 | /** 214 | * Remove elements from `i` up to, but not including, `j` from `v`. 215 | * 216 | * @param v pointer to `scv_vector` 217 | * @param i start index 218 | * @param j end index 219 | * @return zero on success, error code on error 220 | */ 221 | int scv_erase(struct scv_vector *v, size_t i, size_t j); 222 | 223 | /** 224 | * Insert a single element from `data` at the end of `v`. 225 | * 226 | * If `data` is `NULL`, the inserted element is not initialized. 227 | * 228 | * `data` must not point inside `v`. 229 | * 230 | * @param v pointer to `scv_vector` 231 | * @param data pointer to data to copy into new element 232 | * @return zero on success, error code on error 233 | */ 234 | int scv_push_back(struct scv_vector *v, const void *data); 235 | 236 | /** 237 | * Remove the last element of `v`. 238 | * 239 | * @param v pointer to `scv_vector` 240 | * @return zero on success, error code on error 241 | */ 242 | int scv_pop_back(struct scv_vector *v); 243 | 244 | /** 245 | * Resize the number of elements in `v`. 246 | * 247 | * Any new elements are uninitialized. 248 | * 249 | * @param v pointer to `scv_vector` 250 | * @param size new size 251 | * @return zero on success, error code on error 252 | */ 253 | int scv_resize(struct scv_vector *v, size_t size); 254 | 255 | /** 256 | * Copy elements from `src` to `dst`. 257 | * 258 | * @param dst pointer to destination `scv_vector` 259 | * @param src pointer to source `scv_vector` 260 | * @return zero on success, error code on error 261 | */ 262 | int scv_copy(struct scv_vector *dst, const struct scv_vector *src); 263 | 264 | /** 265 | * Swap elements between `scv1` and `scv2`. 266 | * 267 | * @param scv1 pointer to `scv_vector` 268 | * @param scv2 pointer to `scv_vector` 269 | * @return zero on success, error code on error 270 | */ 271 | int scv_swap(struct scv_vector *scv1, struct scv_vector *scv2); 272 | 273 | #ifdef __cplusplus 274 | } /* extern "C" */ 275 | #endif 276 | 277 | #endif /* SCV_H_INCLUDED */ 278 | -------------------------------------------------------------------------------- /test/greatest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2021 Scott Vokes 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef GREATEST_H 18 | #define GREATEST_H 19 | 20 | #if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) 21 | extern "C" { 22 | #endif 23 | 24 | /* 1.5.0 */ 25 | #define GREATEST_VERSION_MAJOR 1 26 | #define GREATEST_VERSION_MINOR 5 27 | #define GREATEST_VERSION_PATCH 0 28 | 29 | /* A unit testing system for C, contained in 1 file. 30 | * It doesn't use dynamic allocation or depend on anything 31 | * beyond ANSI C89. 32 | * 33 | * An up-to-date version can be found at: 34 | * https://github.com/silentbicycle/greatest/ 35 | */ 36 | 37 | 38 | /********************************************************************* 39 | * Minimal test runner template 40 | *********************************************************************/ 41 | #if 0 42 | 43 | #include "greatest.h" 44 | 45 | TEST foo_should_foo(void) { 46 | PASS(); 47 | } 48 | 49 | static void setup_cb(void *data) { 50 | printf("setup callback for each test case\n"); 51 | } 52 | 53 | static void teardown_cb(void *data) { 54 | printf("teardown callback for each test case\n"); 55 | } 56 | 57 | SUITE(suite) { 58 | /* Optional setup/teardown callbacks which will be run before/after 59 | * every test case. If using a test suite, they will be cleared when 60 | * the suite finishes. */ 61 | SET_SETUP(setup_cb, voidp_to_callback_data); 62 | SET_TEARDOWN(teardown_cb, voidp_to_callback_data); 63 | 64 | RUN_TEST(foo_should_foo); 65 | } 66 | 67 | /* Add definitions that need to be in the test runner's main file. */ 68 | GREATEST_MAIN_DEFS(); 69 | 70 | /* Set up, run suite(s) of tests, report pass/fail/skip stats. */ 71 | int run_tests(void) { 72 | GREATEST_INIT(); /* init. greatest internals */ 73 | /* List of suites to run (if any). */ 74 | RUN_SUITE(suite); 75 | 76 | /* Tests can also be run directly, without using test suites. */ 77 | RUN_TEST(foo_should_foo); 78 | 79 | GREATEST_PRINT_REPORT(); /* display results */ 80 | return greatest_all_passed(); 81 | } 82 | 83 | /* main(), for a standalone command-line test runner. 84 | * This replaces run_tests above, and adds command line option 85 | * handling and exiting with a pass/fail status. */ 86 | int main(int argc, char **argv) { 87 | GREATEST_MAIN_BEGIN(); /* init & parse command-line args */ 88 | RUN_SUITE(suite); 89 | GREATEST_MAIN_END(); /* display results */ 90 | } 91 | 92 | #endif 93 | /*********************************************************************/ 94 | 95 | 96 | #include 97 | #include 98 | #include 99 | #include 100 | 101 | /*********** 102 | * Options * 103 | ***********/ 104 | 105 | /* Default column width for non-verbose output. */ 106 | #ifndef GREATEST_DEFAULT_WIDTH 107 | #define GREATEST_DEFAULT_WIDTH 72 108 | #endif 109 | 110 | /* FILE *, for test logging. */ 111 | #ifndef GREATEST_STDOUT 112 | #define GREATEST_STDOUT stdout 113 | #endif 114 | 115 | /* Remove GREATEST_ prefix from most commonly used symbols? */ 116 | #ifndef GREATEST_USE_ABBREVS 117 | #define GREATEST_USE_ABBREVS 1 118 | #endif 119 | 120 | /* Set to 0 to disable all use of setjmp/longjmp. */ 121 | #ifndef GREATEST_USE_LONGJMP 122 | #define GREATEST_USE_LONGJMP 0 123 | #endif 124 | 125 | /* Make it possible to replace fprintf with another 126 | * function with the same interface. */ 127 | #ifndef GREATEST_FPRINTF 128 | #define GREATEST_FPRINTF fprintf 129 | #endif 130 | 131 | #if GREATEST_USE_LONGJMP 132 | #include 133 | #endif 134 | 135 | /* Set to 0 to disable all use of time.h / clock(). */ 136 | #ifndef GREATEST_USE_TIME 137 | #define GREATEST_USE_TIME 1 138 | #endif 139 | 140 | #if GREATEST_USE_TIME 141 | #include 142 | #endif 143 | 144 | /* Floating point type, for ASSERT_IN_RANGE. */ 145 | #ifndef GREATEST_FLOAT 146 | #define GREATEST_FLOAT double 147 | #define GREATEST_FLOAT_FMT "%g" 148 | #endif 149 | 150 | /* Size of buffer for test name + optional '_' separator and suffix */ 151 | #ifndef GREATEST_TESTNAME_BUF_SIZE 152 | #define GREATEST_TESTNAME_BUF_SIZE 128 153 | #endif 154 | 155 | 156 | /********* 157 | * Types * 158 | *********/ 159 | 160 | /* Info for the current running suite. */ 161 | typedef struct greatest_suite_info { 162 | unsigned int tests_run; 163 | unsigned int passed; 164 | unsigned int failed; 165 | unsigned int skipped; 166 | 167 | #if GREATEST_USE_TIME 168 | /* timers, pre/post running suite and individual tests */ 169 | clock_t pre_suite; 170 | clock_t post_suite; 171 | clock_t pre_test; 172 | clock_t post_test; 173 | #endif 174 | } greatest_suite_info; 175 | 176 | /* Type for a suite function. */ 177 | typedef void greatest_suite_cb(void); 178 | 179 | /* Types for setup/teardown callbacks. If non-NULL, these will be run 180 | * and passed the pointer to their additional data. */ 181 | typedef void greatest_setup_cb(void *udata); 182 | typedef void greatest_teardown_cb(void *udata); 183 | 184 | /* Type for an equality comparison between two pointers of the same type. 185 | * Should return non-0 if equal, otherwise 0. 186 | * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ 187 | typedef int greatest_equal_cb(const void *expd, const void *got, void *udata); 188 | 189 | /* Type for a callback that prints a value pointed to by T. 190 | * Return value has the same meaning as printf's. 191 | * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ 192 | typedef int greatest_printf_cb(const void *t, void *udata); 193 | 194 | /* Callbacks for an arbitrary type; needed for type-specific 195 | * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ 196 | typedef struct greatest_type_info { 197 | greatest_equal_cb *equal; 198 | greatest_printf_cb *print; 199 | } greatest_type_info; 200 | 201 | typedef struct greatest_memory_cmp_env { 202 | const unsigned char *exp; 203 | const unsigned char *got; 204 | size_t size; 205 | } greatest_memory_cmp_env; 206 | 207 | /* Callbacks for string and raw memory types. */ 208 | extern greatest_type_info greatest_type_info_string; 209 | extern greatest_type_info greatest_type_info_memory; 210 | 211 | typedef enum { 212 | GREATEST_FLAG_FIRST_FAIL = 0x01, 213 | GREATEST_FLAG_LIST_ONLY = 0x02, 214 | GREATEST_FLAG_ABORT_ON_FAIL = 0x04 215 | } greatest_flag_t; 216 | 217 | /* Internal state for a PRNG, used to shuffle test order. */ 218 | struct greatest_prng { 219 | unsigned char random_order; /* use random ordering? */ 220 | unsigned char initialized; /* is random ordering initialized? */ 221 | unsigned char pad_0[6]; 222 | unsigned long state; /* PRNG state */ 223 | unsigned long count; /* how many tests, this pass */ 224 | unsigned long count_ceil; /* total number of tests */ 225 | unsigned long count_run; /* total tests run */ 226 | unsigned long a; /* LCG multiplier */ 227 | unsigned long c; /* LCG increment */ 228 | unsigned long m; /* LCG modulus, based on count_ceil */ 229 | }; 230 | 231 | /* Struct containing all test runner state. */ 232 | typedef struct greatest_run_info { 233 | unsigned char flags; 234 | unsigned char verbosity; 235 | unsigned char running_test; /* guard for nested RUN_TEST calls */ 236 | unsigned char exact_name_match; 237 | 238 | unsigned int tests_run; /* total test count */ 239 | 240 | /* currently running test suite */ 241 | greatest_suite_info suite; 242 | 243 | /* overall pass/fail/skip counts */ 244 | unsigned int passed; 245 | unsigned int failed; 246 | unsigned int skipped; 247 | unsigned int assertions; 248 | 249 | /* info to print about the most recent failure */ 250 | unsigned int fail_line; 251 | unsigned int pad_1; 252 | const char *fail_file; 253 | const char *msg; 254 | 255 | /* current setup/teardown hooks and userdata */ 256 | greatest_setup_cb *setup; 257 | void *setup_udata; 258 | greatest_teardown_cb *teardown; 259 | void *teardown_udata; 260 | 261 | /* formatting info for ".....s...F"-style output */ 262 | unsigned int col; 263 | unsigned int width; 264 | 265 | /* only run a specific suite or test */ 266 | const char *suite_filter; 267 | const char *test_filter; 268 | const char *test_exclude; 269 | const char *name_suffix; /* print suffix with test name */ 270 | char name_buf[GREATEST_TESTNAME_BUF_SIZE]; 271 | 272 | struct greatest_prng prng[2]; /* 0: suites, 1: tests */ 273 | 274 | #if GREATEST_USE_TIME 275 | /* overall timers */ 276 | clock_t begin; 277 | clock_t end; 278 | #endif 279 | 280 | #if GREATEST_USE_LONGJMP 281 | int pad_jmp_buf; 282 | unsigned char pad_2[4]; 283 | jmp_buf jump_dest; 284 | #endif 285 | } greatest_run_info; 286 | 287 | struct greatest_report_t { 288 | /* overall pass/fail/skip counts */ 289 | unsigned int passed; 290 | unsigned int failed; 291 | unsigned int skipped; 292 | unsigned int assertions; 293 | }; 294 | 295 | /* Global var for the current testing context. 296 | * Initialized by GREATEST_MAIN_DEFS(). */ 297 | extern greatest_run_info greatest_info; 298 | 299 | /* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ 300 | typedef const char *greatest_enum_str_fun(int value); 301 | 302 | 303 | /********************** 304 | * Exported functions * 305 | **********************/ 306 | 307 | /* These are used internally by greatest macros. */ 308 | int greatest_test_pre(const char *name); 309 | void greatest_test_post(int res); 310 | int greatest_do_assert_equal_t(const void *expd, const void *got, 311 | greatest_type_info *type_info, void *udata); 312 | void greatest_prng_init_first_pass(int id); 313 | int greatest_prng_init_second_pass(int id, unsigned long seed); 314 | void greatest_prng_step(int id); 315 | 316 | /* These are part of the public greatest API. */ 317 | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); 318 | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); 319 | void GREATEST_INIT(void); 320 | void GREATEST_PRINT_REPORT(void); 321 | int greatest_all_passed(void); 322 | void greatest_set_suite_filter(const char *filter); 323 | void greatest_set_test_filter(const char *filter); 324 | void greatest_set_test_exclude(const char *filter); 325 | void greatest_set_exact_name_match(void); 326 | void greatest_stop_at_first_fail(void); 327 | void greatest_abort_on_fail(void); 328 | void greatest_list_only(void); 329 | void greatest_get_report(struct greatest_report_t *report); 330 | unsigned int greatest_get_verbosity(void); 331 | void greatest_set_verbosity(unsigned int verbosity); 332 | void greatest_set_flag(greatest_flag_t flag); 333 | void greatest_set_test_suffix(const char *suffix); 334 | 335 | 336 | /******************** 337 | * Language Support * 338 | ********************/ 339 | 340 | /* If __VA_ARGS__ (C99) is supported, allow parametric testing 341 | * without needing to manually manage the argument struct. */ 342 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L) || \ 343 | (defined(_MSC_VER) && _MSC_VER >= 1800) 344 | #define GREATEST_VA_ARGS 345 | #endif 346 | 347 | 348 | /********** 349 | * Macros * 350 | **********/ 351 | 352 | /* Define a suite. (The duplication is intentional -- it eliminates 353 | * a warning from -Wmissing-declarations.) */ 354 | #define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) 355 | 356 | /* Declare a suite, provided by another compilation unit. */ 357 | #define GREATEST_SUITE_EXTERN(NAME) void NAME(void) 358 | 359 | /* Start defining a test function. 360 | * The arguments are not included, to allow parametric testing. */ 361 | #define GREATEST_TEST static enum greatest_test_res 362 | 363 | /* PASS/FAIL/SKIP result from a test. Used internally. */ 364 | typedef enum greatest_test_res { 365 | GREATEST_TEST_RES_PASS = 0, 366 | GREATEST_TEST_RES_FAIL = -1, 367 | GREATEST_TEST_RES_SKIP = 1 368 | } greatest_test_res; 369 | 370 | /* Run a suite. */ 371 | #define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) 372 | 373 | /* Run a test in the current suite. */ 374 | #define GREATEST_RUN_TEST(TEST) \ 375 | do { \ 376 | if (greatest_test_pre(#TEST) == 1) { \ 377 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 378 | if (res == GREATEST_TEST_RES_PASS) { \ 379 | res = TEST(); \ 380 | } \ 381 | greatest_test_post(res); \ 382 | } \ 383 | } while (0) 384 | 385 | /* Ignore a test, don't warn about it being unused. */ 386 | #define GREATEST_IGNORE_TEST(TEST) (void)TEST 387 | 388 | /* Run a test in the current suite with one void * argument, 389 | * which can be a pointer to a struct with multiple arguments. */ 390 | #define GREATEST_RUN_TEST1(TEST, ENV) \ 391 | do { \ 392 | if (greatest_test_pre(#TEST) == 1) { \ 393 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 394 | if (res == GREATEST_TEST_RES_PASS) { \ 395 | res = TEST(ENV); \ 396 | } \ 397 | greatest_test_post(res); \ 398 | } \ 399 | } while (0) 400 | 401 | #ifdef GREATEST_VA_ARGS 402 | #define GREATEST_RUN_TESTp(TEST, ...) \ 403 | do { \ 404 | if (greatest_test_pre(#TEST) == 1) { \ 405 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 406 | if (res == GREATEST_TEST_RES_PASS) { \ 407 | res = TEST(__VA_ARGS__); \ 408 | } \ 409 | greatest_test_post(res); \ 410 | } \ 411 | } while (0) 412 | #endif 413 | 414 | 415 | /* Check if the test runner is in verbose mode. */ 416 | #define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0) 417 | #define GREATEST_LIST_ONLY() \ 418 | (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) 419 | #define GREATEST_FIRST_FAIL() \ 420 | (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) 421 | #define GREATEST_ABORT_ON_FAIL() \ 422 | (greatest_info.flags & GREATEST_FLAG_ABORT_ON_FAIL) 423 | #define GREATEST_FAILURE_ABORT() \ 424 | (GREATEST_FIRST_FAIL() && \ 425 | (greatest_info.suite.failed > 0 || greatest_info.failed > 0)) 426 | 427 | /* Message-less forms of tests defined below. */ 428 | #define GREATEST_PASS() GREATEST_PASSm(NULL) 429 | #define GREATEST_FAIL() GREATEST_FAILm(NULL) 430 | #define GREATEST_SKIP() GREATEST_SKIPm(NULL) 431 | #define GREATEST_ASSERT(COND) \ 432 | GREATEST_ASSERTm(#COND, COND) 433 | #define GREATEST_ASSERT_OR_LONGJMP(COND) \ 434 | GREATEST_ASSERT_OR_LONGJMPm(#COND, COND) 435 | #define GREATEST_ASSERT_FALSE(COND) \ 436 | GREATEST_ASSERT_FALSEm(#COND, COND) 437 | #define GREATEST_ASSERT_EQ(EXP, GOT) \ 438 | GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) 439 | #define GREATEST_ASSERT_NEQ(EXP, GOT) \ 440 | GREATEST_ASSERT_NEQm(#EXP " == " #GOT, EXP, GOT) 441 | #define GREATEST_ASSERT_GT(EXP, GOT) \ 442 | GREATEST_ASSERT_GTm(#EXP " <= " #GOT, EXP, GOT) 443 | #define GREATEST_ASSERT_GTE(EXP, GOT) \ 444 | GREATEST_ASSERT_GTEm(#EXP " < " #GOT, EXP, GOT) 445 | #define GREATEST_ASSERT_LT(EXP, GOT) \ 446 | GREATEST_ASSERT_LTm(#EXP " >= " #GOT, EXP, GOT) 447 | #define GREATEST_ASSERT_LTE(EXP, GOT) \ 448 | GREATEST_ASSERT_LTEm(#EXP " > " #GOT, EXP, GOT) 449 | #define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ 450 | GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT) 451 | #define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ 452 | GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL) 453 | #define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ 454 | GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA) 455 | #define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ 456 | GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT) 457 | #define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ 458 | GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) 459 | #define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ 460 | GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) 461 | #define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ 462 | GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) 463 | 464 | /* The following forms take an additional message argument first, 465 | * to be displayed by the test runner. */ 466 | 467 | /* Fail if a condition is not true, with message. */ 468 | #define GREATEST_ASSERTm(MSG, COND) \ 469 | do { \ 470 | greatest_info.assertions++; \ 471 | if (!(COND)) { GREATEST_FAILm(MSG); } \ 472 | } while (0) 473 | 474 | /* Fail if a condition is not true, longjmping out of test. */ 475 | #define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ 476 | do { \ 477 | greatest_info.assertions++; \ 478 | if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); } \ 479 | } while (0) 480 | 481 | /* Fail if a condition is not false, with message. */ 482 | #define GREATEST_ASSERT_FALSEm(MSG, COND) \ 483 | do { \ 484 | greatest_info.assertions++; \ 485 | if ((COND)) { GREATEST_FAILm(MSG); } \ 486 | } while (0) 487 | 488 | /* Internal macro for relational assertions */ 489 | #define GREATEST__REL(REL, MSG, EXP, GOT) \ 490 | do { \ 491 | greatest_info.assertions++; \ 492 | if (!((EXP) REL (GOT))) { GREATEST_FAILm(MSG); } \ 493 | } while (0) 494 | 495 | /* Fail if EXP is not ==, !=, >, <, >=, or <= to GOT. */ 496 | #define GREATEST_ASSERT_EQm(MSG,E,G) GREATEST__REL(==, MSG,E,G) 497 | #define GREATEST_ASSERT_NEQm(MSG,E,G) GREATEST__REL(!=, MSG,E,G) 498 | #define GREATEST_ASSERT_GTm(MSG,E,G) GREATEST__REL(>, MSG,E,G) 499 | #define GREATEST_ASSERT_GTEm(MSG,E,G) GREATEST__REL(>=, MSG,E,G) 500 | #define GREATEST_ASSERT_LTm(MSG,E,G) GREATEST__REL(<, MSG,E,G) 501 | #define GREATEST_ASSERT_LTEm(MSG,E,G) GREATEST__REL(<=, MSG,E,G) 502 | 503 | /* Fail if EXP != GOT (equality comparison by ==). 504 | * Warning: FMT, EXP, and GOT will be evaluated more 505 | * than once on failure. */ 506 | #define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ 507 | do { \ 508 | greatest_info.assertions++; \ 509 | if ((EXP) != (GOT)) { \ 510 | GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ 511 | GREATEST_FPRINTF(GREATEST_STDOUT, FMT, EXP); \ 512 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ 513 | GREATEST_FPRINTF(GREATEST_STDOUT, FMT, GOT); \ 514 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 515 | GREATEST_FAILm(MSG); \ 516 | } \ 517 | } while (0) 518 | 519 | /* Fail if EXP is not equal to GOT, printing enum IDs. */ 520 | #define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ 521 | do { \ 522 | int greatest_EXP = (int)(EXP); \ 523 | int greatest_GOT = (int)(GOT); \ 524 | greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ 525 | if (greatest_EXP != greatest_GOT) { \ 526 | GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: %s", \ 527 | greatest_ENUM_STR(greatest_EXP)); \ 528 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: %s\n", \ 529 | greatest_ENUM_STR(greatest_GOT)); \ 530 | GREATEST_FAILm(MSG); \ 531 | } \ 532 | } while (0) \ 533 | 534 | /* Fail if GOT not in range of EXP +|- TOL. */ 535 | #define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ 536 | do { \ 537 | GREATEST_FLOAT greatest_EXP = (EXP); \ 538 | GREATEST_FLOAT greatest_GOT = (GOT); \ 539 | GREATEST_FLOAT greatest_TOL = (TOL); \ 540 | greatest_info.assertions++; \ 541 | if ((greatest_EXP > greatest_GOT && \ 542 | greatest_EXP - greatest_GOT > greatest_TOL) || \ 543 | (greatest_EXP < greatest_GOT && \ 544 | greatest_GOT - greatest_EXP > greatest_TOL)) { \ 545 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 546 | "\nExpected: " GREATEST_FLOAT_FMT \ 547 | " +/- " GREATEST_FLOAT_FMT \ 548 | "\n Got: " GREATEST_FLOAT_FMT \ 549 | "\n", \ 550 | greatest_EXP, greatest_TOL, greatest_GOT); \ 551 | GREATEST_FAILm(MSG); \ 552 | } \ 553 | } while (0) 554 | 555 | /* Fail if EXP is not equal to GOT, according to strcmp. */ 556 | #define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ 557 | do { \ 558 | GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ 559 | &greatest_type_info_string, NULL); \ 560 | } while (0) \ 561 | 562 | /* Fail if EXP is not equal to GOT, according to strncmp. */ 563 | #define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ 564 | do { \ 565 | size_t size = SIZE; \ 566 | GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ 567 | &greatest_type_info_string, &size); \ 568 | } while (0) \ 569 | 570 | /* Fail if EXP is not equal to GOT, according to memcmp. */ 571 | #define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ 572 | do { \ 573 | greatest_memory_cmp_env env; \ 574 | env.exp = (const unsigned char *)EXP; \ 575 | env.got = (const unsigned char *)GOT; \ 576 | env.size = SIZE; \ 577 | GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got, \ 578 | &greatest_type_info_memory, &env); \ 579 | } while (0) \ 580 | 581 | /* Fail if EXP is not equal to GOT, according to a comparison 582 | * callback in TYPE_INFO. If they are not equal, optionally use a 583 | * print callback in TYPE_INFO to print them. */ 584 | #define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ 585 | do { \ 586 | greatest_type_info *type_info = (TYPE_INFO); \ 587 | greatest_info.assertions++; \ 588 | if (!greatest_do_assert_equal_t(EXP, GOT, \ 589 | type_info, UDATA)) { \ 590 | if (type_info == NULL || type_info->equal == NULL) { \ 591 | GREATEST_FAILm("type_info->equal callback missing!"); \ 592 | } else { \ 593 | GREATEST_FAILm(MSG); \ 594 | } \ 595 | } \ 596 | } while (0) \ 597 | 598 | /* Pass. */ 599 | #define GREATEST_PASSm(MSG) \ 600 | do { \ 601 | greatest_info.msg = MSG; \ 602 | return GREATEST_TEST_RES_PASS; \ 603 | } while (0) 604 | 605 | /* Fail. */ 606 | #define GREATEST_FAILm(MSG) \ 607 | do { \ 608 | greatest_info.fail_file = __FILE__; \ 609 | greatest_info.fail_line = __LINE__; \ 610 | greatest_info.msg = MSG; \ 611 | if (GREATEST_ABORT_ON_FAIL()) { abort(); } \ 612 | return GREATEST_TEST_RES_FAIL; \ 613 | } while (0) 614 | 615 | /* Optional GREATEST_FAILm variant that longjmps. */ 616 | #if GREATEST_USE_LONGJMP 617 | #define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL) 618 | #define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ 619 | do { \ 620 | greatest_info.fail_file = __FILE__; \ 621 | greatest_info.fail_line = __LINE__; \ 622 | greatest_info.msg = MSG; \ 623 | longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ 624 | } while (0) 625 | #endif 626 | 627 | /* Skip the current test. */ 628 | #define GREATEST_SKIPm(MSG) \ 629 | do { \ 630 | greatest_info.msg = MSG; \ 631 | return GREATEST_TEST_RES_SKIP; \ 632 | } while (0) 633 | 634 | /* Check the result of a subfunction using ASSERT, etc. */ 635 | #define GREATEST_CHECK_CALL(RES) \ 636 | do { \ 637 | enum greatest_test_res greatest_RES = RES; \ 638 | if (greatest_RES != GREATEST_TEST_RES_PASS) { \ 639 | return greatest_RES; \ 640 | } \ 641 | } while (0) \ 642 | 643 | #if GREATEST_USE_TIME 644 | #define GREATEST_SET_TIME(NAME) \ 645 | NAME = clock(); \ 646 | if (NAME == (clock_t) -1) { \ 647 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 648 | "clock error: %s\n", #NAME); \ 649 | exit(EXIT_FAILURE); \ 650 | } 651 | 652 | #define GREATEST_CLOCK_DIFF(C1, C2) \ 653 | GREATEST_FPRINTF(GREATEST_STDOUT, " (%lu ticks, %.3f sec)", \ 654 | (long unsigned int) (C2) - (long unsigned int)(C1), \ 655 | (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) 656 | #else 657 | #define GREATEST_SET_TIME(UNUSED) 658 | #define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2) 659 | #endif 660 | 661 | #if GREATEST_USE_LONGJMP 662 | #define GREATEST_SAVE_CONTEXT() \ 663 | /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call * \ 664 | * so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ 665 | ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) 666 | #else 667 | #define GREATEST_SAVE_CONTEXT() \ 668 | /*a no-op, since setjmp/longjmp aren't being used */ \ 669 | GREATEST_TEST_RES_PASS 670 | #endif 671 | 672 | /* Run every suite / test function run within BODY in pseudo-random 673 | * order, seeded by SEED. (The top 3 bits of the seed are ignored.) 674 | * 675 | * This should be called like: 676 | * GREATEST_SHUFFLE_TESTS(seed, { 677 | * GREATEST_RUN_TEST(some_test); 678 | * GREATEST_RUN_TEST(some_other_test); 679 | * GREATEST_RUN_TEST(yet_another_test); 680 | * }); 681 | * 682 | * Note that the body of the second argument will be evaluated 683 | * multiple times. */ 684 | #define GREATEST_SHUFFLE_SUITES(SD, BODY) GREATEST_SHUFFLE(0, SD, BODY) 685 | #define GREATEST_SHUFFLE_TESTS(SD, BODY) GREATEST_SHUFFLE(1, SD, BODY) 686 | #define GREATEST_SHUFFLE(ID, SD, BODY) \ 687 | do { \ 688 | struct greatest_prng *prng = &greatest_info.prng[ID]; \ 689 | greatest_prng_init_first_pass(ID); \ 690 | do { \ 691 | prng->count = 0; \ 692 | if (prng->initialized) { greatest_prng_step(ID); } \ 693 | BODY; \ 694 | if (!prng->initialized) { \ 695 | if (!greatest_prng_init_second_pass(ID, SD)) { break; } \ 696 | } else if (prng->count_run == prng->count_ceil) { \ 697 | break; \ 698 | } \ 699 | } while (!GREATEST_FAILURE_ABORT()); \ 700 | prng->count_run = prng->random_order = prng->initialized = 0; \ 701 | } while(0) 702 | 703 | /* Include several function definitions in the main test file. */ 704 | #define GREATEST_MAIN_DEFS() \ 705 | \ 706 | /* Is FILTER a subset of NAME? */ \ 707 | static int greatest_name_match(const char *name, const char *filter, \ 708 | int res_if_none) { \ 709 | size_t offset = 0; \ 710 | size_t filter_len = filter ? strlen(filter) : 0; \ 711 | if (filter_len == 0) { return res_if_none; } /* no filter */ \ 712 | if (greatest_info.exact_name_match && strlen(name) != filter_len) { \ 713 | return 0; /* ignore substring matches */ \ 714 | } \ 715 | while (name[offset] != '\0') { \ 716 | if (name[offset] == filter[0]) { \ 717 | if (0 == strncmp(&name[offset], filter, filter_len)) { \ 718 | return 1; \ 719 | } \ 720 | } \ 721 | offset++; \ 722 | } \ 723 | \ 724 | return 0; \ 725 | } \ 726 | \ 727 | static void greatest_buffer_test_name(const char *name) { \ 728 | struct greatest_run_info *g = &greatest_info; \ 729 | size_t len = strlen(name), size = sizeof(g->name_buf); \ 730 | memset(g->name_buf, 0x00, size); \ 731 | (void)strncat(g->name_buf, name, size - 1); \ 732 | if (g->name_suffix && (len + 1 < size)) { \ 733 | g->name_buf[len] = '_'; \ 734 | strncat(&g->name_buf[len+1], g->name_suffix, size-(len+2)); \ 735 | } \ 736 | } \ 737 | \ 738 | /* Before running a test, check the name filtering and \ 739 | * test shuffling state, if applicable, and then call setup hooks. */ \ 740 | int greatest_test_pre(const char *name) { \ 741 | struct greatest_run_info *g = &greatest_info; \ 742 | int match; \ 743 | greatest_buffer_test_name(name); \ 744 | match = greatest_name_match(g->name_buf, g->test_filter, 1) && \ 745 | !greatest_name_match(g->name_buf, g->test_exclude, 0); \ 746 | if (GREATEST_LIST_ONLY()) { /* just listing test names */ \ 747 | if (match) { \ 748 | GREATEST_FPRINTF(GREATEST_STDOUT, " %s\n", g->name_buf); \ 749 | } \ 750 | goto clear; \ 751 | } \ 752 | if (match && (!GREATEST_FIRST_FAIL() || g->suite.failed == 0)) { \ 753 | struct greatest_prng *p = &g->prng[1]; \ 754 | if (p->random_order) { \ 755 | p->count++; \ 756 | if (!p->initialized || ((p->count - 1) != p->state)) { \ 757 | goto clear; /* don't run this test yet */ \ 758 | } \ 759 | } \ 760 | if (g->running_test) { \ 761 | fprintf(stderr, "Error: Test run inside another test.\n"); \ 762 | return 0; \ 763 | } \ 764 | GREATEST_SET_TIME(g->suite.pre_test); \ 765 | if (g->setup) { g->setup(g->setup_udata); } \ 766 | p->count_run++; \ 767 | g->running_test = 1; \ 768 | return 1; /* test should be run */ \ 769 | } else { \ 770 | goto clear; /* skipped */ \ 771 | } \ 772 | clear: \ 773 | g->name_suffix = NULL; \ 774 | return 0; \ 775 | } \ 776 | \ 777 | static void greatest_do_pass(void) { \ 778 | struct greatest_run_info *g = &greatest_info; \ 779 | if (GREATEST_IS_VERBOSE()) { \ 780 | GREATEST_FPRINTF(GREATEST_STDOUT, "PASS %s: %s", \ 781 | g->name_buf, g->msg ? g->msg : ""); \ 782 | } else { \ 783 | GREATEST_FPRINTF(GREATEST_STDOUT, "."); \ 784 | } \ 785 | g->suite.passed++; \ 786 | } \ 787 | \ 788 | static void greatest_do_fail(void) { \ 789 | struct greatest_run_info *g = &greatest_info; \ 790 | if (GREATEST_IS_VERBOSE()) { \ 791 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 792 | "FAIL %s: %s (%s:%u)", g->name_buf, \ 793 | g->msg ? g->msg : "", g->fail_file, g->fail_line); \ 794 | } else { \ 795 | GREATEST_FPRINTF(GREATEST_STDOUT, "F"); \ 796 | g->col++; /* add linebreak if in line of '.'s */ \ 797 | if (g->col != 0) { \ 798 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 799 | g->col = 0; \ 800 | } \ 801 | GREATEST_FPRINTF(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n", \ 802 | g->name_buf, g->msg ? g->msg : "", \ 803 | g->fail_file, g->fail_line); \ 804 | } \ 805 | g->suite.failed++; \ 806 | } \ 807 | \ 808 | static void greatest_do_skip(void) { \ 809 | struct greatest_run_info *g = &greatest_info; \ 810 | if (GREATEST_IS_VERBOSE()) { \ 811 | GREATEST_FPRINTF(GREATEST_STDOUT, "SKIP %s: %s", \ 812 | g->name_buf, g->msg ? g->msg : ""); \ 813 | } else { \ 814 | GREATEST_FPRINTF(GREATEST_STDOUT, "s"); \ 815 | } \ 816 | g->suite.skipped++; \ 817 | } \ 818 | \ 819 | void greatest_test_post(int res) { \ 820 | GREATEST_SET_TIME(greatest_info.suite.post_test); \ 821 | if (greatest_info.teardown) { \ 822 | void *udata = greatest_info.teardown_udata; \ 823 | greatest_info.teardown(udata); \ 824 | } \ 825 | \ 826 | greatest_info.running_test = 0; \ 827 | if (res <= GREATEST_TEST_RES_FAIL) { \ 828 | greatest_do_fail(); \ 829 | } else if (res >= GREATEST_TEST_RES_SKIP) { \ 830 | greatest_do_skip(); \ 831 | } else if (res == GREATEST_TEST_RES_PASS) { \ 832 | greatest_do_pass(); \ 833 | } \ 834 | greatest_info.name_suffix = NULL; \ 835 | greatest_info.suite.tests_run++; \ 836 | greatest_info.col++; \ 837 | if (GREATEST_IS_VERBOSE()) { \ 838 | GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ 839 | greatest_info.suite.post_test); \ 840 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 841 | } else if (greatest_info.col % greatest_info.width == 0) { \ 842 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 843 | greatest_info.col = 0; \ 844 | } \ 845 | fflush(GREATEST_STDOUT); \ 846 | } \ 847 | \ 848 | static void report_suite(void) { \ 849 | if (greatest_info.suite.tests_run > 0) { \ 850 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 851 | "\n%u test%s - %u passed, %u failed, %u skipped", \ 852 | greatest_info.suite.tests_run, \ 853 | greatest_info.suite.tests_run == 1 ? "" : "s", \ 854 | greatest_info.suite.passed, \ 855 | greatest_info.suite.failed, \ 856 | greatest_info.suite.skipped); \ 857 | GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ 858 | greatest_info.suite.post_suite); \ 859 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 860 | } \ 861 | } \ 862 | \ 863 | static void update_counts_and_reset_suite(void) { \ 864 | greatest_info.setup = NULL; \ 865 | greatest_info.setup_udata = NULL; \ 866 | greatest_info.teardown = NULL; \ 867 | greatest_info.teardown_udata = NULL; \ 868 | greatest_info.passed += greatest_info.suite.passed; \ 869 | greatest_info.failed += greatest_info.suite.failed; \ 870 | greatest_info.skipped += greatest_info.suite.skipped; \ 871 | greatest_info.tests_run += greatest_info.suite.tests_run; \ 872 | memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ 873 | greatest_info.col = 0; \ 874 | } \ 875 | \ 876 | static int greatest_suite_pre(const char *suite_name) { \ 877 | struct greatest_prng *p = &greatest_info.prng[0]; \ 878 | if (!greatest_name_match(suite_name, greatest_info.suite_filter, 1) \ 879 | || (GREATEST_FAILURE_ABORT())) { return 0; } \ 880 | if (p->random_order) { \ 881 | p->count++; \ 882 | if (!p->initialized || ((p->count - 1) != p->state)) { \ 883 | return 0; /* don't run this suite yet */ \ 884 | } \ 885 | } \ 886 | p->count_run++; \ 887 | update_counts_and_reset_suite(); \ 888 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ 889 | GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ 890 | return 1; \ 891 | } \ 892 | \ 893 | static void greatest_suite_post(void) { \ 894 | GREATEST_SET_TIME(greatest_info.suite.post_suite); \ 895 | report_suite(); \ 896 | } \ 897 | \ 898 | static void greatest_run_suite(greatest_suite_cb *suite_cb, \ 899 | const char *suite_name) { \ 900 | if (greatest_suite_pre(suite_name)) { \ 901 | suite_cb(); \ 902 | greatest_suite_post(); \ 903 | } \ 904 | } \ 905 | \ 906 | int greatest_do_assert_equal_t(const void *expd, const void *got, \ 907 | greatest_type_info *type_info, void *udata) { \ 908 | int eq = 0; \ 909 | if (type_info == NULL || type_info->equal == NULL) { return 0; } \ 910 | eq = type_info->equal(expd, got, udata); \ 911 | if (!eq) { \ 912 | if (type_info->print != NULL) { \ 913 | GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ 914 | (void)type_info->print(expd, udata); \ 915 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ 916 | (void)type_info->print(got, udata); \ 917 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 918 | } \ 919 | } \ 920 | return eq; \ 921 | } \ 922 | \ 923 | static void greatest_usage(const char *name) { \ 924 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 925 | "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ 926 | " -h, --help print this Help\n" \ 927 | " -l List suites and tests, then exit (dry run)\n" \ 928 | " -f Stop runner after first failure\n" \ 929 | " -a Abort on first failure (implies -f)\n" \ 930 | " -v Verbose output\n" \ 931 | " -s SUITE only run suites containing substring SUITE\n" \ 932 | " -t TEST only run tests containing substring TEST\n" \ 933 | " -e only run exact name match for -s or -t\n" \ 934 | " -x EXCLUDE exclude tests containing substring EXCLUDE\n", \ 935 | name); \ 936 | } \ 937 | \ 938 | static void greatest_parse_options(int argc, char **argv) { \ 939 | int i = 0; \ 940 | for (i = 1; i < argc; i++) { \ 941 | if (argv[i][0] == '-') { \ 942 | char f = argv[i][1]; \ 943 | if ((f == 's' || f == 't' || f == 'x') && argc <= i + 1) { \ 944 | greatest_usage(argv[0]); exit(EXIT_FAILURE); \ 945 | } \ 946 | switch (f) { \ 947 | case 's': /* suite name filter */ \ 948 | greatest_set_suite_filter(argv[i + 1]); i++; break; \ 949 | case 't': /* test name filter */ \ 950 | greatest_set_test_filter(argv[i + 1]); i++; break; \ 951 | case 'x': /* test name exclusion */ \ 952 | greatest_set_test_exclude(argv[i + 1]); i++; break; \ 953 | case 'e': /* exact name match */ \ 954 | greatest_set_exact_name_match(); break; \ 955 | case 'f': /* first fail flag */ \ 956 | greatest_stop_at_first_fail(); break; \ 957 | case 'a': /* abort() on fail flag */ \ 958 | greatest_abort_on_fail(); break; \ 959 | case 'l': /* list only (dry run) */ \ 960 | greatest_list_only(); break; \ 961 | case 'v': /* first fail flag */ \ 962 | greatest_info.verbosity++; break; \ 963 | case 'h': /* help */ \ 964 | greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ 965 | default: \ 966 | case '-': \ 967 | if (0 == strncmp("--help", argv[i], 6)) { \ 968 | greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ 969 | } else if (0 == strcmp("--", argv[i])) { \ 970 | return; /* ignore following arguments */ \ 971 | } \ 972 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 973 | "Unknown argument '%s'\n", argv[i]); \ 974 | greatest_usage(argv[0]); \ 975 | exit(EXIT_FAILURE); \ 976 | } \ 977 | } \ 978 | } \ 979 | } \ 980 | \ 981 | int greatest_all_passed(void) { return (greatest_info.failed == 0); } \ 982 | \ 983 | void greatest_set_test_filter(const char *filter) { \ 984 | greatest_info.test_filter = filter; \ 985 | } \ 986 | \ 987 | void greatest_set_test_exclude(const char *filter) { \ 988 | greatest_info.test_exclude = filter; \ 989 | } \ 990 | \ 991 | void greatest_set_suite_filter(const char *filter) { \ 992 | greatest_info.suite_filter = filter; \ 993 | } \ 994 | \ 995 | void greatest_set_exact_name_match(void) { \ 996 | greatest_info.exact_name_match = 1; \ 997 | } \ 998 | \ 999 | void greatest_stop_at_first_fail(void) { \ 1000 | greatest_set_flag(GREATEST_FLAG_FIRST_FAIL); \ 1001 | } \ 1002 | \ 1003 | void greatest_abort_on_fail(void) { \ 1004 | greatest_set_flag(GREATEST_FLAG_ABORT_ON_FAIL); \ 1005 | } \ 1006 | \ 1007 | void greatest_list_only(void) { \ 1008 | greatest_set_flag(GREATEST_FLAG_LIST_ONLY); \ 1009 | } \ 1010 | \ 1011 | void greatest_get_report(struct greatest_report_t *report) { \ 1012 | if (report) { \ 1013 | report->passed = greatest_info.passed; \ 1014 | report->failed = greatest_info.failed; \ 1015 | report->skipped = greatest_info.skipped; \ 1016 | report->assertions = greatest_info.assertions; \ 1017 | } \ 1018 | } \ 1019 | \ 1020 | unsigned int greatest_get_verbosity(void) { \ 1021 | return greatest_info.verbosity; \ 1022 | } \ 1023 | \ 1024 | void greatest_set_verbosity(unsigned int verbosity) { \ 1025 | greatest_info.verbosity = (unsigned char)verbosity; \ 1026 | } \ 1027 | \ 1028 | void greatest_set_flag(greatest_flag_t flag) { \ 1029 | greatest_info.flags = (unsigned char)(greatest_info.flags | flag); \ 1030 | } \ 1031 | \ 1032 | void greatest_set_test_suffix(const char *suffix) { \ 1033 | greatest_info.name_suffix = suffix; \ 1034 | } \ 1035 | \ 1036 | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ 1037 | greatest_info.setup = cb; \ 1038 | greatest_info.setup_udata = udata; \ 1039 | } \ 1040 | \ 1041 | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) { \ 1042 | greatest_info.teardown = cb; \ 1043 | greatest_info.teardown_udata = udata; \ 1044 | } \ 1045 | \ 1046 | static int greatest_string_equal_cb(const void *expd, const void *got, \ 1047 | void *udata) { \ 1048 | size_t *size = (size_t *)udata; \ 1049 | return (size != NULL \ 1050 | ? (0 == strncmp((const char *)expd, (const char *)got, *size)) \ 1051 | : (0 == strcmp((const char *)expd, (const char *)got))); \ 1052 | } \ 1053 | \ 1054 | static int greatest_string_printf_cb(const void *t, void *udata) { \ 1055 | (void)udata; /* note: does not check \0 termination. */ \ 1056 | return GREATEST_FPRINTF(GREATEST_STDOUT, "%s", (const char *)t); \ 1057 | } \ 1058 | \ 1059 | greatest_type_info greatest_type_info_string = { \ 1060 | greatest_string_equal_cb, greatest_string_printf_cb, \ 1061 | }; \ 1062 | \ 1063 | static int greatest_memory_equal_cb(const void *expd, const void *got, \ 1064 | void *udata) { \ 1065 | greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ 1066 | return (0 == memcmp(expd, got, env->size)); \ 1067 | } \ 1068 | \ 1069 | /* Hexdump raw memory, with differences highlighted */ \ 1070 | static int greatest_memory_printf_cb(const void *t, void *udata) { \ 1071 | greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ 1072 | const unsigned char *buf = (const unsigned char *)t; \ 1073 | unsigned char diff_mark = ' '; \ 1074 | FILE *out = GREATEST_STDOUT; \ 1075 | size_t i, line_i, line_len = 0; \ 1076 | int len = 0; /* format hexdump with differences highlighted */ \ 1077 | for (i = 0; i < env->size; i+= line_len) { \ 1078 | diff_mark = ' '; \ 1079 | line_len = env->size - i; \ 1080 | if (line_len > 16) { line_len = 16; } \ 1081 | for (line_i = i; line_i < i + line_len; line_i++) { \ 1082 | if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X'; \ 1083 | } \ 1084 | len += GREATEST_FPRINTF(out, "\n%04x %c ", \ 1085 | (unsigned int)i, diff_mark); \ 1086 | for (line_i = i; line_i < i + line_len; line_i++) { \ 1087 | int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ 1088 | len += GREATEST_FPRINTF(out, "%02x%c", \ 1089 | buf[line_i], m ? ' ' : '<'); \ 1090 | } \ 1091 | for (line_i = 0; line_i < 16 - line_len; line_i++) { \ 1092 | len += GREATEST_FPRINTF(out, " "); \ 1093 | } \ 1094 | GREATEST_FPRINTF(out, " "); \ 1095 | for (line_i = i; line_i < i + line_len; line_i++) { \ 1096 | unsigned char c = buf[line_i]; \ 1097 | len += GREATEST_FPRINTF(out, "%c", isprint(c) ? c : '.'); \ 1098 | } \ 1099 | } \ 1100 | len += GREATEST_FPRINTF(out, "\n"); \ 1101 | return len; \ 1102 | } \ 1103 | \ 1104 | void greatest_prng_init_first_pass(int id) { \ 1105 | greatest_info.prng[id].random_order = 1; \ 1106 | greatest_info.prng[id].count_run = 0; \ 1107 | } \ 1108 | \ 1109 | int greatest_prng_init_second_pass(int id, unsigned long seed) { \ 1110 | struct greatest_prng *p = &greatest_info.prng[id]; \ 1111 | if (p->count == 0) { return 0; } \ 1112 | p->count_ceil = p->count; \ 1113 | for (p->m = 1; p->m < p->count; p->m <<= 1) {} \ 1114 | p->state = seed & 0x1fffffff; /* only use lower 29 bits */ \ 1115 | p->a = 4LU * p->state; /* to avoid overflow when */ \ 1116 | p->a = (p->a ? p->a : 4) | 1; /* multiplied by 4 */ \ 1117 | p->c = 2147483647; /* and so p->c ((2 ** 31) - 1) is */ \ 1118 | p->initialized = 1; /* always relatively prime to p->a. */ \ 1119 | fprintf(stderr, "init_second_pass: a %lu, c %lu, state %lu\n", \ 1120 | p->a, p->c, p->state); \ 1121 | return 1; \ 1122 | } \ 1123 | \ 1124 | /* Step the pseudorandom number generator until its state reaches \ 1125 | * another test ID between 0 and the test count. \ 1126 | * This use a linear congruential pseudorandom number generator, \ 1127 | * with the power-of-two ceiling of the test count as the modulus, the \ 1128 | * masked seed as the multiplier, and a prime as the increment. For \ 1129 | * each generated value < the test count, run the corresponding test. \ 1130 | * This will visit all IDs 0 <= X < mod once before repeating, \ 1131 | * with a starting position chosen based on the initial seed. \ 1132 | * For details, see: Knuth, The Art of Computer Programming \ 1133 | * Volume. 2, section 3.2.1. */ \ 1134 | void greatest_prng_step(int id) { \ 1135 | struct greatest_prng *p = &greatest_info.prng[id]; \ 1136 | do { \ 1137 | p->state = ((p->a * p->state) + p->c) & (p->m - 1); \ 1138 | } while (p->state >= p->count_ceil); \ 1139 | } \ 1140 | \ 1141 | void GREATEST_INIT(void) { \ 1142 | /* Suppress unused function warning if features aren't used */ \ 1143 | (void)greatest_run_suite; \ 1144 | (void)greatest_parse_options; \ 1145 | (void)greatest_prng_step; \ 1146 | (void)greatest_prng_init_first_pass; \ 1147 | (void)greatest_prng_init_second_pass; \ 1148 | (void)greatest_set_test_suffix; \ 1149 | \ 1150 | memset(&greatest_info, 0, sizeof(greatest_info)); \ 1151 | greatest_info.width = GREATEST_DEFAULT_WIDTH; \ 1152 | GREATEST_SET_TIME(greatest_info.begin); \ 1153 | } \ 1154 | \ 1155 | /* Report passes, failures, skipped tests, the number of \ 1156 | * assertions, and the overall run time. */ \ 1157 | void GREATEST_PRINT_REPORT(void) { \ 1158 | if (!GREATEST_LIST_ONLY()) { \ 1159 | update_counts_and_reset_suite(); \ 1160 | GREATEST_SET_TIME(greatest_info.end); \ 1161 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 1162 | "\nTotal: %u test%s", \ 1163 | greatest_info.tests_run, \ 1164 | greatest_info.tests_run == 1 ? "" : "s"); \ 1165 | GREATEST_CLOCK_DIFF(greatest_info.begin, \ 1166 | greatest_info.end); \ 1167 | GREATEST_FPRINTF(GREATEST_STDOUT, ", %u assertion%s\n", \ 1168 | greatest_info.assertions, \ 1169 | greatest_info.assertions == 1 ? "" : "s"); \ 1170 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 1171 | "Pass: %u, fail: %u, skip: %u.\n", \ 1172 | greatest_info.passed, \ 1173 | greatest_info.failed, greatest_info.skipped); \ 1174 | } \ 1175 | } \ 1176 | \ 1177 | greatest_type_info greatest_type_info_memory = { \ 1178 | greatest_memory_equal_cb, greatest_memory_printf_cb, \ 1179 | }; \ 1180 | \ 1181 | greatest_run_info greatest_info 1182 | 1183 | /* Handle command-line arguments, etc. */ 1184 | #define GREATEST_MAIN_BEGIN() \ 1185 | do { \ 1186 | GREATEST_INIT(); \ 1187 | greatest_parse_options(argc, argv); \ 1188 | } while (0) 1189 | 1190 | /* Report results, exit with exit status based on results. */ 1191 | #define GREATEST_MAIN_END() \ 1192 | do { \ 1193 | GREATEST_PRINT_REPORT(); \ 1194 | return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ 1195 | } while (0) 1196 | 1197 | /* Make abbreviations without the GREATEST_ prefix for the 1198 | * most commonly used symbols. */ 1199 | #if GREATEST_USE_ABBREVS 1200 | #define TEST GREATEST_TEST 1201 | #define SUITE GREATEST_SUITE 1202 | #define SUITE_EXTERN GREATEST_SUITE_EXTERN 1203 | #define RUN_TEST GREATEST_RUN_TEST 1204 | #define RUN_TEST1 GREATEST_RUN_TEST1 1205 | #define RUN_SUITE GREATEST_RUN_SUITE 1206 | #define IGNORE_TEST GREATEST_IGNORE_TEST 1207 | #define ASSERT GREATEST_ASSERT 1208 | #define ASSERTm GREATEST_ASSERTm 1209 | #define ASSERT_FALSE GREATEST_ASSERT_FALSE 1210 | #define ASSERT_EQ GREATEST_ASSERT_EQ 1211 | #define ASSERT_NEQ GREATEST_ASSERT_NEQ 1212 | #define ASSERT_GT GREATEST_ASSERT_GT 1213 | #define ASSERT_GTE GREATEST_ASSERT_GTE 1214 | #define ASSERT_LT GREATEST_ASSERT_LT 1215 | #define ASSERT_LTE GREATEST_ASSERT_LTE 1216 | #define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT 1217 | #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE 1218 | #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T 1219 | #define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ 1220 | #define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ 1221 | #define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ 1222 | #define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ 1223 | #define ASSERT_FALSEm GREATEST_ASSERT_FALSEm 1224 | #define ASSERT_EQm GREATEST_ASSERT_EQm 1225 | #define ASSERT_NEQm GREATEST_ASSERT_NEQm 1226 | #define ASSERT_GTm GREATEST_ASSERT_GTm 1227 | #define ASSERT_GTEm GREATEST_ASSERT_GTEm 1228 | #define ASSERT_LTm GREATEST_ASSERT_LTm 1229 | #define ASSERT_LTEm GREATEST_ASSERT_LTEm 1230 | #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm 1231 | #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm 1232 | #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm 1233 | #define ASSERT_STR_EQm GREATEST_ASSERT_STR_EQm 1234 | #define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm 1235 | #define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm 1236 | #define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm 1237 | #define PASS GREATEST_PASS 1238 | #define FAIL GREATEST_FAIL 1239 | #define SKIP GREATEST_SKIP 1240 | #define PASSm GREATEST_PASSm 1241 | #define FAILm GREATEST_FAILm 1242 | #define SKIPm GREATEST_SKIPm 1243 | #define SET_SETUP GREATEST_SET_SETUP_CB 1244 | #define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB 1245 | #define CHECK_CALL GREATEST_CHECK_CALL 1246 | #define SHUFFLE_TESTS GREATEST_SHUFFLE_TESTS 1247 | #define SHUFFLE_SUITES GREATEST_SHUFFLE_SUITES 1248 | 1249 | #ifdef GREATEST_VA_ARGS 1250 | #define RUN_TESTp GREATEST_RUN_TESTp 1251 | #endif 1252 | 1253 | #if GREATEST_USE_LONGJMP 1254 | #define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP 1255 | #define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm 1256 | #define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP 1257 | #define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm 1258 | #endif 1259 | 1260 | #endif /* USE_ABBREVS */ 1261 | 1262 | #if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) 1263 | } 1264 | #endif 1265 | 1266 | #endif 1267 | -------------------------------------------------------------------------------- /test/test_scv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * scv - Simple C Vector 3 | * 4 | * test_scv.c 5 | * 6 | * Copyright 2003-2014 Joergen Ibsen 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * SPDX-License-Identifier: Apache-2.0 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "greatest.h" 27 | 28 | #include "scv.h" 29 | 30 | #ifndef ARRAY_SIZE 31 | # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 32 | #endif 33 | 34 | static int check_int_vector(struct scv_vector *v) 35 | { 36 | size_t i; 37 | int j; 38 | int *p; 39 | 40 | if (scv_objsize(v) != sizeof(int)) { 41 | return 0; 42 | } 43 | 44 | if (scv_empty(v)) { 45 | return 0; 46 | } 47 | 48 | p = scv_data(v); 49 | 50 | for (i = 0, j = 0; i < scv_size(v); ++i, ++j) { 51 | if (p[i] != j) { 52 | return 0; 53 | } 54 | } 55 | 56 | return 1; 57 | } 58 | 59 | /* scv_new */ 60 | 61 | TEST new_objsize_zero(void) 62 | { 63 | struct scv_vector *v; 64 | 65 | v = scv_new(0, 1); 66 | 67 | ASSERT(v == NULL); 68 | 69 | PASS(); 70 | } 71 | 72 | TEST new_capacity_zero(void) 73 | { 74 | struct scv_vector *v; 75 | 76 | v = scv_new(1, 0); 77 | 78 | ASSERT(v != NULL); 79 | 80 | scv_delete(v); 81 | 82 | PASS(); 83 | } 84 | 85 | TEST new_objsize_max(void) 86 | { 87 | struct scv_vector *v; 88 | 89 | v = scv_new((size_t) -1, 0); 90 | 91 | ASSERT(v == NULL); 92 | 93 | PASS(); 94 | } 95 | 96 | TEST new_capacity_max(void) 97 | { 98 | struct scv_vector *v; 99 | 100 | v = scv_new(1, (size_t) -1); 101 | 102 | ASSERT(v == NULL); 103 | 104 | PASS(); 105 | } 106 | 107 | /* scv_delete */ 108 | 109 | TEST delete_null(void) 110 | { 111 | scv_delete(NULL); 112 | 113 | PASS(); 114 | } 115 | 116 | /* scv_at */ 117 | 118 | TEST at_inside(void) 119 | { 120 | struct scv_vector *v; 121 | int *p; 122 | 123 | v = scv_new(sizeof(int), 25); 124 | 125 | scv_insert(v, 0, NULL, 5); 126 | 127 | p = scv_at(v, 1); 128 | 129 | ASSERT(p != NULL && p == (int *) v->data + 1); 130 | 131 | scv_delete(v); 132 | 133 | PASS(); 134 | } 135 | 136 | TEST at_outside(void) 137 | { 138 | struct scv_vector *v; 139 | int *p; 140 | 141 | v = scv_new(sizeof(int), 25); 142 | 143 | scv_insert(v, 0, NULL, 5); 144 | 145 | p = scv_at(v, 6); 146 | 147 | ASSERT(p == NULL); 148 | 149 | scv_delete(v); 150 | 151 | PASS(); 152 | } 153 | 154 | TEST at_empty(void) 155 | { 156 | struct scv_vector *v; 157 | int *p; 158 | 159 | v = scv_new(sizeof(int), 25); 160 | 161 | p = scv_at(v, 0); 162 | 163 | ASSERT(p == NULL); 164 | 165 | scv_delete(v); 166 | 167 | PASS(); 168 | } 169 | 170 | /* scv_front */ 171 | 172 | TEST front_nonempty(void) 173 | { 174 | struct scv_vector *v; 175 | int *p; 176 | 177 | v = scv_new(sizeof(int), 25); 178 | 179 | scv_insert(v, 0, NULL, 5); 180 | 181 | p = scv_front(v); 182 | 183 | ASSERT(p != NULL && p == (int *) v->data); 184 | 185 | scv_delete(v); 186 | 187 | PASS(); 188 | } 189 | 190 | TEST front_empty(void) 191 | { 192 | struct scv_vector *v; 193 | int *p; 194 | 195 | v = scv_new(sizeof(int), 25); 196 | 197 | p = scv_front(v); 198 | 199 | ASSERT(p == NULL); 200 | 201 | scv_delete(v); 202 | 203 | PASS(); 204 | } 205 | 206 | /* scv_back */ 207 | 208 | TEST back_nonempty(void) 209 | { 210 | struct scv_vector *v; 211 | int *p; 212 | 213 | v = scv_new(sizeof(int), 25); 214 | 215 | scv_insert(v, 0, NULL, 5); 216 | 217 | p = scv_back(v); 218 | 219 | ASSERT(p != NULL && p == (int *) v->data + 4); 220 | 221 | scv_delete(v); 222 | 223 | PASS(); 224 | } 225 | 226 | TEST back_single(void) 227 | { 228 | struct scv_vector *v; 229 | int *p; 230 | 231 | v = scv_new(sizeof(int), 25); 232 | 233 | scv_insert(v, 0, NULL, 1); 234 | 235 | p = scv_back(v); 236 | 237 | ASSERT(p != NULL && p == (int *) v->data); 238 | 239 | scv_delete(v); 240 | 241 | PASS(); 242 | } 243 | 244 | TEST back_empty(void) 245 | { 246 | struct scv_vector *v; 247 | int *p; 248 | 249 | v = scv_new(sizeof(int), 25); 250 | 251 | p = scv_back(v); 252 | 253 | ASSERT(p == NULL); 254 | 255 | scv_delete(v); 256 | 257 | PASS(); 258 | } 259 | 260 | /* scv_data */ 261 | 262 | TEST data_nonempty(void) 263 | { 264 | struct scv_vector *v; 265 | int *p; 266 | 267 | v = scv_new(sizeof(int), 25); 268 | 269 | scv_insert(v, 0, NULL, 5); 270 | 271 | p = scv_data(v); 272 | 273 | ASSERT(p != NULL && p == (int *) v->data); 274 | 275 | scv_delete(v); 276 | 277 | PASS(); 278 | } 279 | 280 | TEST data_empty(void) 281 | { 282 | struct scv_vector *v; 283 | int *p; 284 | 285 | v = scv_new(sizeof(int), 25); 286 | 287 | p = scv_data(v); 288 | 289 | ASSERT(p == NULL); 290 | 291 | scv_delete(v); 292 | 293 | PASS(); 294 | } 295 | 296 | /* scv_empty */ 297 | 298 | TEST empty_empty(void) 299 | { 300 | struct scv_vector *v; 301 | int res; 302 | 303 | v = scv_new(1, 100); 304 | 305 | res = scv_empty(v); 306 | 307 | ASSERT(res != 0); 308 | 309 | scv_delete(v); 310 | 311 | PASS(); 312 | } 313 | 314 | TEST empty_nonempty(void) 315 | { 316 | struct scv_vector *v; 317 | int res; 318 | 319 | v = scv_new(1, 100); 320 | 321 | scv_resize(v, 1); 322 | 323 | res = scv_empty(v); 324 | 325 | ASSERT(res == 0); 326 | 327 | scv_delete(v); 328 | 329 | PASS(); 330 | } 331 | 332 | /* scv_size */ 333 | 334 | TEST size_empty(void) 335 | { 336 | struct scv_vector *v; 337 | 338 | v = scv_new(3, 25); 339 | 340 | ASSERT(v != NULL && scv_size(v) == 0); 341 | 342 | scv_delete(v); 343 | 344 | PASS(); 345 | } 346 | 347 | TEST size_nonempty(void) 348 | { 349 | struct scv_vector *v; 350 | 351 | v = scv_new(3, 25); 352 | 353 | scv_resize(v, 10); 354 | 355 | ASSERT(v != NULL && scv_size(v) == 10); 356 | 357 | scv_delete(v); 358 | 359 | PASS(); 360 | } 361 | 362 | /* scv_objsize */ 363 | 364 | TEST objsize(void) 365 | { 366 | struct scv_vector *v; 367 | 368 | v = scv_new(3, 25); 369 | 370 | ASSERT(v != NULL && scv_objsize(v) == 3); 371 | 372 | scv_delete(v); 373 | 374 | PASS(); 375 | } 376 | 377 | /* scv_reserve */ 378 | 379 | TEST reserve_zero(void) 380 | { 381 | struct scv_vector *v; 382 | int res; 383 | 384 | v = scv_new(1, 100); 385 | 386 | res = scv_reserve(v, 0); 387 | 388 | ASSERT(res == SCV_OK && scv_capacity(v) == 100); 389 | 390 | scv_delete(v); 391 | 392 | PASS(); 393 | } 394 | 395 | TEST reserve_below_size(void) 396 | { 397 | struct scv_vector *v; 398 | int res; 399 | 400 | v = scv_new(1, 120); 401 | 402 | scv_resize(v, 100); 403 | 404 | res = scv_reserve(v, 80); 405 | 406 | ASSERT(res == SCV_OK && scv_size(v) == 100 && scv_capacity(v) == 120); 407 | 408 | scv_delete(v); 409 | 410 | PASS(); 411 | } 412 | 413 | TEST reserve_equals_size(void) 414 | { 415 | struct scv_vector *v; 416 | int res; 417 | 418 | v = scv_new(1, 120); 419 | 420 | scv_resize(v, 100); 421 | 422 | res = scv_reserve(v, 100); 423 | 424 | ASSERT(res == SCV_OK && scv_size(v) == 100 && scv_capacity(v) == 120); 425 | 426 | scv_delete(v); 427 | 428 | PASS(); 429 | } 430 | 431 | TEST reserve_above_size(void) 432 | { 433 | struct scv_vector *v; 434 | int res; 435 | 436 | v = scv_new(1, 120); 437 | 438 | scv_resize(v, 100); 439 | 440 | res = scv_reserve(v, 110); 441 | 442 | ASSERT(res == SCV_OK && scv_size(v) == 100 && scv_capacity(v) == 120); 443 | 444 | scv_delete(v); 445 | 446 | PASS(); 447 | } 448 | 449 | TEST reserve_above_capacity(void) 450 | { 451 | struct scv_vector *v; 452 | int res; 453 | 454 | v = scv_new(1, 120); 455 | 456 | scv_resize(v, 100); 457 | 458 | res = scv_reserve(v, 140); 459 | 460 | ASSERT(res == SCV_OK && scv_size(v) == 100 && scv_capacity(v) == 140); 461 | 462 | scv_delete(v); 463 | 464 | PASS(); 465 | } 466 | 467 | TEST reserve_capacity_max(void) 468 | { 469 | struct scv_vector *v; 470 | int res; 471 | 472 | v = scv_new(1, 100); 473 | 474 | res = scv_reserve(v, (size_t) -1); 475 | 476 | ASSERT(res != SCV_OK); 477 | 478 | scv_delete(v); 479 | 480 | PASS(); 481 | } 482 | 483 | /* scv_capacity */ 484 | 485 | TEST capacity(void) 486 | { 487 | struct scv_vector *v; 488 | 489 | v = scv_new(3, 25); 490 | 491 | ASSERT(v != NULL && scv_capacity(v) >= 25); 492 | 493 | scv_delete(v); 494 | 495 | PASS(); 496 | } 497 | 498 | /* scv_shrink_to_fit */ 499 | 500 | TEST shrink_to_fit_empty(void) 501 | { 502 | struct scv_vector *v; 503 | int res; 504 | 505 | v = scv_new(1, 100); 506 | 507 | res = scv_shrink_to_fit(v); 508 | 509 | ASSERT(res == SCV_OK && scv_capacity(v) > 0); 510 | 511 | scv_delete(v); 512 | 513 | PASS(); 514 | } 515 | 516 | TEST shrink_to_fit_size_equals_capacity(void) 517 | { 518 | struct scv_vector *v; 519 | int res; 520 | 521 | v = scv_new(1, 100); 522 | 523 | scv_resize(v, 100); 524 | 525 | res = scv_shrink_to_fit(v); 526 | 527 | ASSERT(res == SCV_OK && scv_size(v) == scv_capacity(v)); 528 | 529 | scv_delete(v); 530 | 531 | PASS(); 532 | } 533 | 534 | TEST shrink_to_fit_size_below_capacity(void) 535 | { 536 | struct scv_vector *v; 537 | int res; 538 | 539 | v = scv_new(1, 100); 540 | 541 | scv_resize(v, 80); 542 | 543 | res = scv_shrink_to_fit(v); 544 | 545 | ASSERT(res == SCV_OK && scv_size(v) == scv_capacity(v)); 546 | 547 | scv_delete(v); 548 | 549 | PASS(); 550 | } 551 | 552 | /* scv_clear */ 553 | 554 | TEST clear_nonempty(void) 555 | { 556 | struct scv_vector *v; 557 | int res; 558 | 559 | v = scv_new(sizeof(int), 25); 560 | 561 | scv_insert(v, 0, NULL, 5); 562 | 563 | res = scv_clear(v); 564 | 565 | ASSERT(res == SCV_OK && scv_size(v) == 0 && scv_capacity(v) == 25); 566 | 567 | scv_delete(v); 568 | 569 | PASS(); 570 | } 571 | 572 | TEST clear_empty(void) 573 | { 574 | struct scv_vector *v; 575 | int res; 576 | 577 | v = scv_new(sizeof(int), 25); 578 | 579 | res = scv_clear(v); 580 | 581 | ASSERT(res == SCV_OK && scv_size(v) == 0 && scv_capacity(v) == 25); 582 | 583 | scv_delete(v); 584 | 585 | PASS(); 586 | } 587 | 588 | /* scv_assign */ 589 | 590 | TEST assign_empty_and_nonempty(void) 591 | { 592 | struct scv_vector *v; 593 | const int data[] = { 0, 1, 2, 3, 4 }; 594 | int res; 595 | 596 | v = scv_new(sizeof(int), 25); 597 | 598 | ASSERT(scv_size(v) == 0); 599 | 600 | res = scv_assign(v, NULL, 0); 601 | 602 | ASSERT(res == SCV_OK && scv_capacity(v) == 25 && scv_size(v) == 0); 603 | 604 | res = scv_assign(v, data, ARRAY_SIZE(data)); 605 | 606 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 607 | ASSERT(check_int_vector(v)); 608 | 609 | res = scv_assign(v, NULL, 0); 610 | 611 | ASSERT(res == SCV_OK && scv_size(v) == 0); 612 | 613 | scv_delete(v); 614 | 615 | PASS(); 616 | } 617 | 618 | TEST assign_less(void) 619 | { 620 | struct scv_vector *v; 621 | const int data1[] = { -1, -1, -1, -1, -1, -1, -1 }; 622 | const int data2[] = { 0, 1, 2, 3, 4 }; 623 | int res; 624 | 625 | v = scv_new(sizeof(int), 25); 626 | 627 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 628 | 629 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 630 | 631 | res = scv_assign(v, data2, ARRAY_SIZE(data2)); 632 | 633 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data2)); 634 | ASSERT(check_int_vector(v)); 635 | 636 | scv_delete(v); 637 | 638 | PASS(); 639 | } 640 | 641 | TEST assign_more(void) 642 | { 643 | struct scv_vector *v; 644 | const int data1[] = { -1, -1, -1 }; 645 | const int data2[] = { 0, 1, 2, 3, 4 }; 646 | int res; 647 | 648 | v = scv_new(sizeof(int), 25); 649 | 650 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 651 | 652 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 653 | 654 | res = scv_assign(v, data2, ARRAY_SIZE(data2)); 655 | 656 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data2)); 657 | ASSERT(check_int_vector(v)); 658 | 659 | scv_delete(v); 660 | 661 | PASS(); 662 | } 663 | 664 | TEST assign_null_data(void) 665 | { 666 | struct scv_vector *v; 667 | int res; 668 | 669 | v = scv_new(sizeof(int), 25); 670 | 671 | ASSERT(scv_size(v) == 0); 672 | 673 | res = scv_assign(v, NULL, 50); 674 | 675 | ASSERT(res == SCV_OK && scv_size(v) == 50); 676 | 677 | scv_delete(v); 678 | 679 | PASS(); 680 | } 681 | 682 | TEST assign_growing_capacity(void) 683 | { 684 | struct scv_vector *v; 685 | const int data1[] = { -1, -1, -1 }; 686 | int data2[50]; 687 | int res; 688 | size_t i; 689 | 690 | for (i = 0; i < ARRAY_SIZE(data2); ++i) { 691 | data2[i] = (int) i; 692 | } 693 | 694 | v = scv_new(sizeof(int), 25); 695 | 696 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 697 | 698 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 699 | ASSERT(scv_capacity(v) == 25); 700 | 701 | res = scv_assign(v, data2, ARRAY_SIZE(data2)); 702 | 703 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data2)); 704 | ASSERT(scv_capacity(v) >= ARRAY_SIZE(data2)); 705 | ASSERT(check_int_vector(v)); 706 | 707 | scv_delete(v); 708 | 709 | PASS(); 710 | } 711 | 712 | TEST assign_nobj_max(void) 713 | { 714 | struct scv_vector *v; 715 | int res; 716 | 717 | v = scv_new(sizeof(int), 25); 718 | 719 | res = scv_assign(v, NULL, (size_t) -1); 720 | 721 | ASSERT(res != SCV_OK && scv_size(v) == 0); 722 | 723 | scv_delete(v); 724 | 725 | PASS(); 726 | } 727 | 728 | /* scv_replace */ 729 | 730 | TEST replace_empty_vector(void) 731 | { 732 | struct scv_vector *v; 733 | const int data[] = { 0, 1, 2, 3, 4 }; 734 | int res; 735 | 736 | v = scv_new(sizeof(int), 25); 737 | 738 | res = scv_replace(v, 0, 0, data, ARRAY_SIZE(data)); 739 | 740 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 741 | ASSERT(check_int_vector(v)); 742 | 743 | scv_delete(v); 744 | 745 | PASS(); 746 | } 747 | 748 | TEST replace_empty_range_start(void) 749 | { 750 | struct scv_vector *v; 751 | const int data1[] = { 2, 3, 4 }; 752 | const int data2[] = { 0, 1 }; 753 | int res; 754 | 755 | v = scv_new(sizeof(int), 25); 756 | 757 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 758 | 759 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 760 | 761 | res = scv_replace(v, 0, 0, data2, ARRAY_SIZE(data2)); 762 | 763 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 764 | ASSERT(check_int_vector(v)); 765 | 766 | scv_delete(v); 767 | 768 | PASS(); 769 | } 770 | 771 | TEST replace_empty_range_middle(void) 772 | { 773 | struct scv_vector *v; 774 | const int data1[] = { 0, 1, 4 }; 775 | const int data2[] = { 2, 3 }; 776 | int res; 777 | 778 | v = scv_new(sizeof(int), 25); 779 | 780 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 781 | 782 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 783 | 784 | res = scv_replace(v, 2, 2, data2, ARRAY_SIZE(data2)); 785 | 786 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 787 | ASSERT(check_int_vector(v)); 788 | 789 | scv_delete(v); 790 | 791 | PASS(); 792 | } 793 | 794 | TEST replace_empty_range_end(void) 795 | { 796 | struct scv_vector *v; 797 | const int data1[] = { 0, 1, 2 }; 798 | const int data2[] = { 3, 4 }; 799 | int res; 800 | 801 | v = scv_new(sizeof(int), 25); 802 | 803 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 804 | 805 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 806 | 807 | res = scv_replace(v, 3, 3, data2, ARRAY_SIZE(data2)); 808 | 809 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 810 | ASSERT(check_int_vector(v)); 811 | 812 | scv_delete(v); 813 | 814 | PASS(); 815 | } 816 | 817 | TEST replace_start(void) 818 | { 819 | struct scv_vector *v; 820 | const int data1[] = { -1, -1, 2, 3, 4 }; 821 | const int data2[] = { 0, 1 }; 822 | int res; 823 | 824 | v = scv_new(sizeof(int), 25); 825 | 826 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 827 | 828 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 829 | 830 | res = scv_replace(v, 0, 2, data2, ARRAY_SIZE(data2)); 831 | 832 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 833 | ASSERT(check_int_vector(v)); 834 | 835 | scv_delete(v); 836 | 837 | PASS(); 838 | } 839 | 840 | TEST replace_middle(void) 841 | { 842 | struct scv_vector *v; 843 | const int data1[] = { 0, 1, -1, -1, 4 }; 844 | const int data2[] = { 2, 3 }; 845 | int res; 846 | 847 | v = scv_new(sizeof(int), 25); 848 | 849 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 850 | 851 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 852 | 853 | res = scv_replace(v, 2, 4, data2, ARRAY_SIZE(data2)); 854 | 855 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 856 | ASSERT(check_int_vector(v)); 857 | 858 | scv_delete(v); 859 | 860 | PASS(); 861 | } 862 | 863 | TEST replace_end(void) 864 | { 865 | struct scv_vector *v; 866 | const int data1[] = { 0, 1, 2, -1, -1 }; 867 | const int data2[] = { 3, 4 }; 868 | int res; 869 | 870 | v = scv_new(sizeof(int), 25); 871 | 872 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 873 | 874 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 875 | 876 | res = scv_replace(v, 3, scv_size(v), data2, ARRAY_SIZE(data2)); 877 | 878 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 879 | ASSERT(check_int_vector(v)); 880 | 881 | scv_delete(v); 882 | 883 | PASS(); 884 | } 885 | 886 | TEST replace_start_with_nothing(void) 887 | { 888 | struct scv_vector *v; 889 | const int data[] = { -1, -1, 0, 1, 2, 3, 4 }; 890 | int res; 891 | 892 | v = scv_new(sizeof(int), 25); 893 | 894 | res = scv_assign(v, data, ARRAY_SIZE(data)); 895 | 896 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 897 | 898 | res = scv_replace(v, 0, 2, NULL, 0); 899 | 900 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 2); 901 | ASSERT(check_int_vector(v)); 902 | 903 | scv_delete(v); 904 | 905 | PASS(); 906 | } 907 | 908 | TEST replace_middle_with_nothing(void) 909 | { 910 | struct scv_vector *v; 911 | const int data[] = { 0, 1, -1, -1, 2, 3, 4 }; 912 | int res; 913 | 914 | v = scv_new(sizeof(int), 25); 915 | 916 | res = scv_assign(v, data, ARRAY_SIZE(data)); 917 | 918 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 919 | 920 | res = scv_replace(v, 2, 4, NULL, 0); 921 | 922 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 2); 923 | ASSERT(check_int_vector(v)); 924 | 925 | scv_delete(v); 926 | 927 | PASS(); 928 | } 929 | 930 | TEST replace_end_with_nothing(void) 931 | { 932 | struct scv_vector *v; 933 | const int data[] = { 0, 1, 2, 3, 4, -1, -1 }; 934 | int res; 935 | 936 | v = scv_new(sizeof(int), 25); 937 | 938 | res = scv_assign(v, data, ARRAY_SIZE(data)); 939 | 940 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 941 | 942 | res = scv_replace(v, scv_size(v) - 2, scv_size(v), NULL, 0); 943 | 944 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 2); 945 | ASSERT(check_int_vector(v)); 946 | 947 | scv_delete(v); 948 | 949 | PASS(); 950 | } 951 | 952 | TEST replace_with_less(void) 953 | { 954 | struct scv_vector *v; 955 | const int data1[] = { 0, 1, -1, -1, -1, 4 }; 956 | const int data2[] = { 2, 3 }; 957 | int res; 958 | 959 | v = scv_new(sizeof(int), 25); 960 | 961 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 962 | 963 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 964 | 965 | res = scv_replace(v, 2, 5, data2, ARRAY_SIZE(data2)); 966 | 967 | ASSERT(res == SCV_OK && scv_size(v) == 5); 968 | ASSERT(check_int_vector(v)); 969 | 970 | scv_delete(v); 971 | 972 | PASS(); 973 | } 974 | 975 | TEST replace_with_more(void) 976 | { 977 | struct scv_vector *v; 978 | const int data1[] = { 0, 1, -1, 4 }; 979 | const int data2[] = { 2, 3 }; 980 | int res; 981 | 982 | v = scv_new(sizeof(int), 25); 983 | 984 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 985 | 986 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 987 | 988 | res = scv_replace(v, 2, 3, data2, ARRAY_SIZE(data2)); 989 | 990 | ASSERT(res == SCV_OK && scv_size(v) == 5); 991 | ASSERT(check_int_vector(v)); 992 | 993 | scv_delete(v); 994 | 995 | PASS(); 996 | } 997 | 998 | TEST replace_all_with_less(void) 999 | { 1000 | struct scv_vector *v; 1001 | const int data1[] = { -1, -1, -1, -1, -1, -1, -1 }; 1002 | const int data2[] = { 0, 1, 2, 3, 4 }; 1003 | int res; 1004 | 1005 | v = scv_new(sizeof(int), 25); 1006 | 1007 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 1008 | 1009 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1010 | 1011 | res = scv_replace(v, 0, scv_size(v), data2, ARRAY_SIZE(data2)); 1012 | 1013 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data2)); 1014 | ASSERT(check_int_vector(v)); 1015 | 1016 | scv_delete(v); 1017 | 1018 | PASS(); 1019 | } 1020 | 1021 | TEST replace_all_with_more(void) 1022 | { 1023 | struct scv_vector *v; 1024 | const int data1[] = { -1, -1, -1 }; 1025 | const int data2[] = { 0, 1, 2, 3, 4 }; 1026 | int res; 1027 | 1028 | v = scv_new(sizeof(int), 25); 1029 | 1030 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 1031 | 1032 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1033 | 1034 | res = scv_replace(v, 0, scv_size(v), data2, ARRAY_SIZE(data2)); 1035 | 1036 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data2)); 1037 | ASSERT(check_int_vector(v)); 1038 | 1039 | scv_delete(v); 1040 | 1041 | PASS(); 1042 | } 1043 | 1044 | TEST replace_with_null_data(void) 1045 | { 1046 | struct scv_vector *v; 1047 | const int data[] = { -1, -1, -1 }; 1048 | int res; 1049 | 1050 | v = scv_new(sizeof(int), 25); 1051 | 1052 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1053 | 1054 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1055 | 1056 | res = scv_replace(v, 0, scv_size(v), NULL, 50); 1057 | 1058 | ASSERT(res == SCV_OK && scv_size(v) == 50); 1059 | 1060 | scv_delete(v); 1061 | 1062 | PASS(); 1063 | } 1064 | 1065 | TEST replace_growing_capacity(void) 1066 | { 1067 | struct scv_vector *v; 1068 | const int data1[] = { 45, 46, 47, 48, 49 }; 1069 | int data2[45]; 1070 | int res; 1071 | size_t i; 1072 | 1073 | for (i = 0; i < ARRAY_SIZE(data2); ++i) { 1074 | data2[i] = (int) i; 1075 | } 1076 | 1077 | v = scv_new(sizeof(int), 25); 1078 | 1079 | res = scv_assign(v, data1, ARRAY_SIZE(data1)); 1080 | 1081 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1082 | 1083 | res = scv_replace(v, 0, 0, data2, ARRAY_SIZE(data2)); 1084 | 1085 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 1086 | ASSERT(check_int_vector(v)); 1087 | 1088 | scv_delete(v); 1089 | 1090 | PASS(); 1091 | } 1092 | 1093 | TEST replace_nobj_max(void) 1094 | { 1095 | struct scv_vector *v; 1096 | int res; 1097 | 1098 | v = scv_new(sizeof(int), 25); 1099 | 1100 | res = scv_replace(v, 0, 0, NULL, (size_t) -1); 1101 | 1102 | ASSERT(res != SCV_OK && scv_size(v) == 0); 1103 | 1104 | scv_delete(v); 1105 | 1106 | PASS(); 1107 | } 1108 | 1109 | TEST replace_outside_range(void) 1110 | { 1111 | struct scv_vector *v; 1112 | const int data[] = { 0, 1, 2, 3, 4 }; 1113 | int res; 1114 | 1115 | v = scv_new(sizeof(int), 25); 1116 | 1117 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1118 | 1119 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1120 | 1121 | res = scv_replace(v, 2, scv_size(v) + 1, NULL, 0); 1122 | 1123 | ASSERT(res != SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1124 | ASSERT(check_int_vector(v)); 1125 | 1126 | scv_delete(v); 1127 | 1128 | PASS(); 1129 | } 1130 | 1131 | TEST replace_negative_range(void) 1132 | { 1133 | struct scv_vector *v; 1134 | const int data[] = { 0, 1, 2, 3, 4 }; 1135 | int res; 1136 | 1137 | v = scv_new(sizeof(int), 25); 1138 | 1139 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1140 | 1141 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1142 | 1143 | res = scv_replace(v, 3, 2, NULL, 1); 1144 | 1145 | ASSERT(res != SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1146 | ASSERT(check_int_vector(v)); 1147 | 1148 | scv_delete(v); 1149 | 1150 | PASS(); 1151 | } 1152 | 1153 | /* scv_insert */ 1154 | 1155 | TEST insert_empty_vector(void) 1156 | { 1157 | struct scv_vector *v; 1158 | const int data[] = { 0, 1, 2, 3, 4 }; 1159 | int res; 1160 | 1161 | v = scv_new(sizeof(int), 25); 1162 | 1163 | res = scv_insert(v, 0, data, ARRAY_SIZE(data)); 1164 | 1165 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1166 | ASSERT(check_int_vector(v)); 1167 | 1168 | scv_delete(v); 1169 | 1170 | PASS(); 1171 | } 1172 | 1173 | TEST insert_start(void) 1174 | { 1175 | struct scv_vector *v; 1176 | const int data1[] = { 2, 3, 4 }; 1177 | const int data2[] = { 0, 1 }; 1178 | int res; 1179 | 1180 | v = scv_new(sizeof(int), 25); 1181 | 1182 | res = scv_insert(v, 0, data1, ARRAY_SIZE(data1)); 1183 | 1184 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1185 | 1186 | res = scv_insert(v, 0, data2, ARRAY_SIZE(data2)); 1187 | 1188 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 1189 | ASSERT(check_int_vector(v)); 1190 | 1191 | scv_delete(v); 1192 | 1193 | PASS(); 1194 | } 1195 | 1196 | TEST insert_middle(void) 1197 | { 1198 | struct scv_vector *v; 1199 | const int data1[] = { 0, 1, 4 }; 1200 | const int data2[] = { 2, 3 }; 1201 | int res; 1202 | 1203 | v = scv_new(sizeof(int), 25); 1204 | 1205 | res = scv_insert(v, 0, data1, ARRAY_SIZE(data1)); 1206 | 1207 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1208 | 1209 | res = scv_insert(v, 2, data2, ARRAY_SIZE(data2)); 1210 | 1211 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 1212 | ASSERT(check_int_vector(v)); 1213 | 1214 | scv_delete(v); 1215 | 1216 | PASS(); 1217 | } 1218 | 1219 | TEST insert_end(void) 1220 | { 1221 | struct scv_vector *v; 1222 | const int data1[] = { 0, 1, 2 }; 1223 | const int data2[] = { 3, 4 }; 1224 | int res; 1225 | 1226 | v = scv_new(sizeof(int), 25); 1227 | 1228 | res = scv_insert(v, 0, data1, ARRAY_SIZE(data1)); 1229 | 1230 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1231 | 1232 | res = scv_insert(v, scv_size(v), data2, ARRAY_SIZE(data2)); 1233 | 1234 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 1235 | ASSERT(check_int_vector(v)); 1236 | 1237 | scv_delete(v); 1238 | 1239 | PASS(); 1240 | } 1241 | 1242 | TEST insert_nothing(void) 1243 | { 1244 | struct scv_vector *v; 1245 | const int data[] = { 0, 1, 2, 3, 4 }; 1246 | int res; 1247 | 1248 | v = scv_new(sizeof(int), 25); 1249 | 1250 | res = scv_insert(v, 0, data, ARRAY_SIZE(data)); 1251 | 1252 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1253 | 1254 | res = scv_insert(v, 0, NULL, 0); 1255 | 1256 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1257 | ASSERT(check_int_vector(v)); 1258 | 1259 | res = scv_insert(v, 2, NULL, 0); 1260 | 1261 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1262 | ASSERT(check_int_vector(v)); 1263 | 1264 | res = scv_insert(v, scv_size(v), NULL, 0); 1265 | 1266 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1267 | ASSERT(check_int_vector(v)); 1268 | 1269 | scv_delete(v); 1270 | 1271 | PASS(); 1272 | } 1273 | 1274 | TEST insert_null_data(void) 1275 | { 1276 | struct scv_vector *v; 1277 | const int data[] = { -1, -1, -1 }; 1278 | int res; 1279 | 1280 | v = scv_new(sizeof(int), 25); 1281 | 1282 | res = scv_insert(v, 0, data, ARRAY_SIZE(data)); 1283 | 1284 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1285 | 1286 | res = scv_insert(v, 0, NULL, 50); 1287 | 1288 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) + 50); 1289 | 1290 | scv_delete(v); 1291 | 1292 | PASS(); 1293 | } 1294 | 1295 | TEST insert_growing_capacity(void) 1296 | { 1297 | struct scv_vector *v; 1298 | const int data1[] = { 45, 46, 47, 48, 49 }; 1299 | int data2[45]; 1300 | int res; 1301 | size_t i; 1302 | 1303 | for (i = 0; i < ARRAY_SIZE(data2); ++i) { 1304 | data2[i] = (int) i; 1305 | } 1306 | 1307 | v = scv_new(sizeof(int), 25); 1308 | 1309 | res = scv_insert(v, 0, data1, ARRAY_SIZE(data1)); 1310 | 1311 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1)); 1312 | 1313 | res = scv_insert(v, 0, data2, ARRAY_SIZE(data2)); 1314 | 1315 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data1) + ARRAY_SIZE(data2)); 1316 | ASSERT(check_int_vector(v)); 1317 | 1318 | scv_delete(v); 1319 | 1320 | PASS(); 1321 | } 1322 | 1323 | TEST insert_nobj_max(void) 1324 | { 1325 | struct scv_vector *v; 1326 | int res; 1327 | 1328 | v = scv_new(sizeof(int), 25); 1329 | 1330 | res = scv_insert(v, 0, NULL, (size_t) -1); 1331 | 1332 | ASSERT(res != SCV_OK && scv_size(v) == 0); 1333 | 1334 | scv_delete(v); 1335 | 1336 | PASS(); 1337 | } 1338 | 1339 | TEST insert_outside_range(void) 1340 | { 1341 | struct scv_vector *v; 1342 | const int data[] = { 0, 1, 2, 3, 4 }; 1343 | int res; 1344 | 1345 | v = scv_new(sizeof(int), 25); 1346 | 1347 | res = scv_insert(v, 0, data, ARRAY_SIZE(data)); 1348 | 1349 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1350 | 1351 | res = scv_insert(v, scv_size(v) + 1, NULL, 0); 1352 | 1353 | ASSERT(res != SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1354 | ASSERT(check_int_vector(v)); 1355 | 1356 | scv_delete(v); 1357 | 1358 | PASS(); 1359 | } 1360 | 1361 | /* scv_erase */ 1362 | 1363 | TEST erase_nothing(void) 1364 | { 1365 | struct scv_vector *v; 1366 | int res; 1367 | 1368 | v = scv_new(sizeof(int), 25); 1369 | 1370 | res = scv_erase(v, 0, 0); 1371 | 1372 | ASSERT(res == SCV_OK && scv_size(v) == 0); 1373 | 1374 | scv_resize(v, 10); 1375 | 1376 | res = scv_erase(v, 0, 0); 1377 | 1378 | ASSERT(res == SCV_OK && scv_size(v) == 10); 1379 | 1380 | scv_delete(v); 1381 | 1382 | PASS(); 1383 | } 1384 | 1385 | TEST erase_start(void) 1386 | { 1387 | struct scv_vector *v; 1388 | const int data[] = { -1, -1, 0, 1, 2, 3, 4 }; 1389 | int res; 1390 | 1391 | v = scv_new(sizeof(int), 25); 1392 | 1393 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1394 | 1395 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1396 | 1397 | res = scv_erase(v, 0, 2); 1398 | 1399 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 2); 1400 | ASSERT(check_int_vector(v)); 1401 | 1402 | scv_delete(v); 1403 | 1404 | PASS(); 1405 | } 1406 | 1407 | TEST erase_middle(void) 1408 | { 1409 | struct scv_vector *v; 1410 | const int data[] = { 0, 1, -1, -1, 2, 3, 4 }; 1411 | int res; 1412 | 1413 | v = scv_new(sizeof(int), 25); 1414 | 1415 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1416 | 1417 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1418 | 1419 | res = scv_erase(v, 2, 4); 1420 | 1421 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 2); 1422 | ASSERT(check_int_vector(v)); 1423 | 1424 | scv_delete(v); 1425 | 1426 | PASS(); 1427 | } 1428 | 1429 | TEST erase_end(void) 1430 | { 1431 | struct scv_vector *v; 1432 | const int data[] = { 0, 1, 2, 3, 4, -1, -1 }; 1433 | int res; 1434 | 1435 | v = scv_new(sizeof(int), 25); 1436 | 1437 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1438 | 1439 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1440 | 1441 | res = scv_erase(v, scv_size(v) - 2, scv_size(v)); 1442 | 1443 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 2); 1444 | ASSERT(check_int_vector(v)); 1445 | 1446 | scv_delete(v); 1447 | 1448 | PASS(); 1449 | } 1450 | 1451 | TEST erase_all(void) 1452 | { 1453 | struct scv_vector *v; 1454 | const int data[] = { 0, 1, 2, 3, 4 }; 1455 | int res; 1456 | 1457 | v = scv_new(sizeof(int), 25); 1458 | 1459 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1460 | 1461 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1462 | 1463 | res = scv_erase(v, 0, scv_size(v)); 1464 | 1465 | ASSERT(res == SCV_OK && scv_size(v) == 0); 1466 | 1467 | scv_delete(v); 1468 | 1469 | PASS(); 1470 | } 1471 | 1472 | TEST erase_outside_range(void) 1473 | { 1474 | struct scv_vector *v; 1475 | const int data[] = { 0, 1, 2, 3, 4 }; 1476 | int res; 1477 | 1478 | v = scv_new(sizeof(int), 25); 1479 | 1480 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1481 | 1482 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1483 | 1484 | res = scv_erase(v, 2, scv_size(v) + 1); 1485 | 1486 | ASSERT(res != SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1487 | ASSERT(check_int_vector(v)); 1488 | 1489 | scv_delete(v); 1490 | 1491 | PASS(); 1492 | } 1493 | 1494 | TEST erase_negative_range(void) 1495 | { 1496 | struct scv_vector *v; 1497 | const int data[] = { 0, 1, 2, 3, 4 }; 1498 | int res; 1499 | 1500 | v = scv_new(sizeof(int), 25); 1501 | 1502 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1503 | 1504 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1505 | 1506 | res = scv_erase(v, 3, 2); 1507 | 1508 | ASSERT(res != SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1509 | ASSERT(check_int_vector(v)); 1510 | 1511 | scv_delete(v); 1512 | 1513 | PASS(); 1514 | } 1515 | 1516 | /* scv_push_back */ 1517 | 1518 | TEST push_back_empty(void) 1519 | { 1520 | struct scv_vector *v; 1521 | const int i = 0; 1522 | int res; 1523 | 1524 | v = scv_new(sizeof(int), 25); 1525 | 1526 | res = scv_push_back(v, &i); 1527 | 1528 | ASSERT(res == SCV_OK && scv_size(v) == 1); 1529 | ASSERT(check_int_vector(v)); 1530 | 1531 | scv_delete(v); 1532 | 1533 | PASS(); 1534 | } 1535 | 1536 | TEST push_back(void) 1537 | { 1538 | struct scv_vector *v; 1539 | const int data[] = { 0, 1, 2, 3, 4 }; 1540 | const int i = 5; 1541 | int res; 1542 | 1543 | v = scv_new(sizeof(int), 25); 1544 | 1545 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1546 | 1547 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1548 | 1549 | res = scv_push_back(v, &i); 1550 | 1551 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) + 1); 1552 | ASSERT(check_int_vector(v)); 1553 | 1554 | scv_delete(v); 1555 | 1556 | PASS(); 1557 | } 1558 | 1559 | TEST push_back_growing_capacity(void) 1560 | { 1561 | struct scv_vector *v; 1562 | int i; 1563 | int res; 1564 | 1565 | v = scv_new(sizeof(int), 25); 1566 | 1567 | for (i = 0; i < 30; ++i) { 1568 | res = scv_push_back(v, &i); 1569 | ASSERT(res == SCV_OK && scv_size(v) == (size_t) i + 1); 1570 | ASSERT(check_int_vector(v)); 1571 | } 1572 | 1573 | scv_delete(v); 1574 | 1575 | PASS(); 1576 | } 1577 | 1578 | /* scv_pop_back */ 1579 | 1580 | TEST pop_back(void) 1581 | { 1582 | struct scv_vector *v; 1583 | const int data[] = { 0, 1, 2, 3, 4 }; 1584 | int res; 1585 | 1586 | v = scv_new(sizeof(int), 25); 1587 | 1588 | res = scv_assign(v, data, ARRAY_SIZE(data)); 1589 | 1590 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data)); 1591 | 1592 | res = scv_pop_back(v); 1593 | 1594 | ASSERT(res == SCV_OK && scv_size(v) == ARRAY_SIZE(data) - 1); 1595 | ASSERT(check_int_vector(v)); 1596 | 1597 | scv_delete(v); 1598 | 1599 | PASS(); 1600 | } 1601 | 1602 | TEST pop_back_empty(void) 1603 | { 1604 | struct scv_vector *v; 1605 | int res; 1606 | 1607 | v = scv_new(sizeof(int), 25); 1608 | 1609 | res = scv_pop_back(v); 1610 | 1611 | ASSERT(res != SCV_OK && scv_size(v) == 0); 1612 | 1613 | scv_delete(v); 1614 | 1615 | PASS(); 1616 | } 1617 | 1618 | /* scv_resize */ 1619 | 1620 | TEST resize_zero_size(void) 1621 | { 1622 | struct scv_vector *v; 1623 | int res; 1624 | 1625 | v = scv_new(1, 100); 1626 | 1627 | scv_assign(v, NULL, 50); 1628 | 1629 | res = scv_resize(v, 0); 1630 | 1631 | ASSERT(res == SCV_OK && scv_size(v) == 0); 1632 | 1633 | scv_delete(v); 1634 | 1635 | PASS(); 1636 | } 1637 | 1638 | TEST resize_smaller_size(void) 1639 | { 1640 | struct scv_vector *v; 1641 | int res; 1642 | 1643 | v = scv_new(1, 100); 1644 | 1645 | scv_assign(v, NULL, 50); 1646 | 1647 | res = scv_resize(v, 25); 1648 | 1649 | ASSERT(res == SCV_OK && scv_size(v) == 25); 1650 | 1651 | scv_delete(v); 1652 | 1653 | PASS(); 1654 | } 1655 | 1656 | TEST resize_equal_size(void) 1657 | { 1658 | struct scv_vector *v; 1659 | int res; 1660 | 1661 | v = scv_new(1, 100); 1662 | 1663 | scv_assign(v, NULL, 50); 1664 | 1665 | res = scv_resize(v, 50); 1666 | 1667 | ASSERT(res == SCV_OK && scv_size(v) == 50); 1668 | 1669 | scv_delete(v); 1670 | 1671 | PASS(); 1672 | } 1673 | 1674 | TEST resize_larger_size(void) 1675 | { 1676 | struct scv_vector *v; 1677 | int res; 1678 | 1679 | v = scv_new(1, 100); 1680 | 1681 | scv_assign(v, NULL, 50); 1682 | 1683 | res = scv_resize(v, 75); 1684 | 1685 | ASSERT(res == SCV_OK && scv_size(v) == 75); 1686 | 1687 | scv_delete(v); 1688 | 1689 | PASS(); 1690 | } 1691 | 1692 | TEST resize_larger_capacity(void) 1693 | { 1694 | struct scv_vector *v; 1695 | int res; 1696 | 1697 | v = scv_new(1, 100); 1698 | 1699 | scv_assign(v, NULL, 50); 1700 | 1701 | res = scv_resize(v, 125); 1702 | 1703 | ASSERT(res == SCV_OK && scv_size(v) == 125); 1704 | 1705 | scv_delete(v); 1706 | 1707 | PASS(); 1708 | } 1709 | 1710 | TEST resize_size_max(void) 1711 | { 1712 | struct scv_vector *v; 1713 | int res; 1714 | 1715 | v = scv_new(1, 100); 1716 | 1717 | res = scv_resize(v, (size_t) -1); 1718 | 1719 | ASSERT(res != SCV_OK); 1720 | 1721 | scv_delete(v); 1722 | 1723 | PASS(); 1724 | } 1725 | 1726 | /* scv_copy */ 1727 | 1728 | TEST copy_empty_to_empty(void) 1729 | { 1730 | struct scv_vector *v1; 1731 | struct scv_vector *v2; 1732 | int res; 1733 | 1734 | v1 = scv_new(4, 25); 1735 | v2 = scv_new(4, 50); 1736 | 1737 | res = scv_copy(v1, v2); 1738 | 1739 | ASSERT(res == SCV_OK && scv_capacity(v1) == 25 && scv_size(v1) == 0); 1740 | 1741 | scv_delete(v1); 1742 | scv_delete(v2); 1743 | 1744 | PASS(); 1745 | } 1746 | 1747 | TEST copy_empty_to_nonempty(void) 1748 | { 1749 | struct scv_vector *v1; 1750 | struct scv_vector *v2; 1751 | int res; 1752 | 1753 | v1 = scv_new(4, 25); 1754 | v2 = scv_new(4, 50); 1755 | 1756 | scv_insert(v1, 0, NULL, 5); 1757 | 1758 | res = scv_copy(v1, v2); 1759 | 1760 | ASSERT(res == SCV_OK && scv_capacity(v1) == 25 && scv_size(v1) == 0); 1761 | 1762 | scv_delete(v1); 1763 | scv_delete(v2); 1764 | 1765 | PASS(); 1766 | } 1767 | 1768 | TEST copy_nonempty_to_empty(void) 1769 | { 1770 | struct scv_vector *v1; 1771 | struct scv_vector *v2; 1772 | int res; 1773 | 1774 | v1 = scv_new(4, 25); 1775 | v2 = scv_new(4, 50); 1776 | 1777 | scv_insert(v2, 0, NULL, 5); 1778 | 1779 | res = scv_copy(v1, v2); 1780 | 1781 | ASSERT(res == SCV_OK && scv_capacity(v1) == 25 && scv_size(v1) == 5); 1782 | 1783 | scv_delete(v1); 1784 | scv_delete(v2); 1785 | 1786 | PASS(); 1787 | } 1788 | 1789 | TEST copy_nonempty_to_nonempty(void) 1790 | { 1791 | struct scv_vector *v1; 1792 | struct scv_vector *v2; 1793 | int res; 1794 | 1795 | v1 = scv_new(4, 25); 1796 | v2 = scv_new(4, 50); 1797 | 1798 | scv_insert(v1, 0, NULL, 10); 1799 | scv_insert(v2, 0, NULL, 5); 1800 | 1801 | res = scv_copy(v1, v2); 1802 | 1803 | ASSERT(res == SCV_OK && scv_capacity(v1) == 25 && scv_size(v1) == 5); 1804 | 1805 | scv_delete(v1); 1806 | scv_delete(v2); 1807 | 1808 | PASS(); 1809 | } 1810 | 1811 | TEST copy_objsize_mismatch(void) 1812 | { 1813 | struct scv_vector *v1; 1814 | struct scv_vector *v2; 1815 | int res; 1816 | 1817 | v1 = scv_new(4, 25); 1818 | v2 = scv_new(2, 50); 1819 | 1820 | res = scv_copy(v1, v2); 1821 | 1822 | ASSERT(res != SCV_OK); 1823 | 1824 | scv_delete(v1); 1825 | scv_delete(v2); 1826 | 1827 | PASS(); 1828 | } 1829 | 1830 | TEST copy_to_itself(void) 1831 | { 1832 | struct scv_vector *v; 1833 | int res; 1834 | 1835 | v = scv_new(4, 25); 1836 | 1837 | res = scv_copy(v, v); 1838 | 1839 | ASSERT(res != SCV_OK); 1840 | 1841 | scv_delete(v); 1842 | 1843 | PASS(); 1844 | } 1845 | 1846 | /* scv_swap */ 1847 | 1848 | TEST swap(void) 1849 | { 1850 | struct scv_vector *v1; 1851 | struct scv_vector *v2; 1852 | int res; 1853 | 1854 | v1 = scv_new(1, 100); 1855 | v2 = scv_new(4, 25); 1856 | 1857 | res = scv_swap(v1, v2); 1858 | 1859 | ASSERT(res == SCV_OK && scv_capacity(v1) == 25 && scv_capacity(v2) == 100); 1860 | 1861 | scv_delete(v1); 1862 | scv_delete(v2); 1863 | 1864 | PASS(); 1865 | } 1866 | 1867 | SUITE(scv) 1868 | { 1869 | RUN_TEST(new_objsize_zero); 1870 | RUN_TEST(new_capacity_zero); 1871 | RUN_TEST(new_objsize_max); 1872 | RUN_TEST(new_capacity_max); 1873 | 1874 | RUN_TEST(delete_null); 1875 | 1876 | RUN_TEST(at_inside); 1877 | RUN_TEST(at_outside); 1878 | RUN_TEST(at_empty); 1879 | 1880 | RUN_TEST(front_nonempty); 1881 | RUN_TEST(front_empty); 1882 | 1883 | RUN_TEST(back_nonempty); 1884 | RUN_TEST(back_single); 1885 | RUN_TEST(back_empty); 1886 | 1887 | RUN_TEST(data_nonempty); 1888 | RUN_TEST(data_empty); 1889 | 1890 | RUN_TEST(empty_empty); 1891 | RUN_TEST(empty_nonempty); 1892 | 1893 | RUN_TEST(size_empty); 1894 | RUN_TEST(size_nonempty); 1895 | 1896 | RUN_TEST(objsize); 1897 | 1898 | RUN_TEST(reserve_zero); 1899 | RUN_TEST(reserve_below_size); 1900 | RUN_TEST(reserve_equals_size); 1901 | RUN_TEST(reserve_above_size); 1902 | RUN_TEST(reserve_above_capacity); 1903 | RUN_TEST(reserve_capacity_max); 1904 | 1905 | RUN_TEST(capacity); 1906 | 1907 | RUN_TEST(shrink_to_fit_empty); 1908 | RUN_TEST(shrink_to_fit_size_equals_capacity); 1909 | RUN_TEST(shrink_to_fit_size_below_capacity); 1910 | 1911 | RUN_TEST(clear_nonempty); 1912 | RUN_TEST(clear_empty); 1913 | 1914 | RUN_TEST(assign_empty_and_nonempty); 1915 | RUN_TEST(assign_less); 1916 | RUN_TEST(assign_more); 1917 | RUN_TEST(assign_null_data); 1918 | RUN_TEST(assign_growing_capacity); 1919 | RUN_TEST(assign_nobj_max); 1920 | 1921 | RUN_TEST(replace_empty_vector); 1922 | RUN_TEST(replace_empty_range_start); 1923 | RUN_TEST(replace_empty_range_middle); 1924 | RUN_TEST(replace_empty_range_end); 1925 | RUN_TEST(replace_start); 1926 | RUN_TEST(replace_middle); 1927 | RUN_TEST(replace_end); 1928 | RUN_TEST(replace_start_with_nothing); 1929 | RUN_TEST(replace_middle_with_nothing); 1930 | RUN_TEST(replace_end_with_nothing); 1931 | RUN_TEST(replace_with_less); 1932 | RUN_TEST(replace_with_more); 1933 | RUN_TEST(replace_all_with_less); 1934 | RUN_TEST(replace_all_with_more); 1935 | RUN_TEST(replace_with_null_data); 1936 | RUN_TEST(replace_growing_capacity); 1937 | RUN_TEST(replace_nobj_max); 1938 | RUN_TEST(replace_outside_range); 1939 | RUN_TEST(replace_negative_range); 1940 | 1941 | RUN_TEST(insert_empty_vector); 1942 | RUN_TEST(insert_start); 1943 | RUN_TEST(insert_middle); 1944 | RUN_TEST(insert_end); 1945 | RUN_TEST(insert_nothing); 1946 | RUN_TEST(insert_null_data); 1947 | RUN_TEST(insert_growing_capacity); 1948 | RUN_TEST(insert_nobj_max); 1949 | RUN_TEST(insert_outside_range); 1950 | 1951 | RUN_TEST(erase_nothing); 1952 | RUN_TEST(erase_start); 1953 | RUN_TEST(erase_middle); 1954 | RUN_TEST(erase_end); 1955 | RUN_TEST(erase_all); 1956 | RUN_TEST(erase_outside_range); 1957 | RUN_TEST(erase_negative_range); 1958 | 1959 | RUN_TEST(push_back_empty); 1960 | RUN_TEST(push_back); 1961 | RUN_TEST(push_back_growing_capacity); 1962 | 1963 | RUN_TEST(pop_back); 1964 | RUN_TEST(pop_back_empty); 1965 | 1966 | RUN_TEST(resize_zero_size); 1967 | RUN_TEST(resize_smaller_size); 1968 | RUN_TEST(resize_equal_size); 1969 | RUN_TEST(resize_larger_size); 1970 | RUN_TEST(resize_larger_capacity); 1971 | RUN_TEST(resize_size_max); 1972 | 1973 | RUN_TEST(copy_empty_to_empty); 1974 | RUN_TEST(copy_empty_to_nonempty); 1975 | RUN_TEST(copy_nonempty_to_empty); 1976 | RUN_TEST(copy_nonempty_to_nonempty); 1977 | RUN_TEST(copy_objsize_mismatch); 1978 | RUN_TEST(copy_to_itself); 1979 | 1980 | RUN_TEST(swap); 1981 | } 1982 | 1983 | GREATEST_MAIN_DEFS(); 1984 | 1985 | int main(int argc, char *argv[]) 1986 | { 1987 | GREATEST_MAIN_BEGIN(); 1988 | RUN_SUITE(scv); 1989 | GREATEST_MAIN_END(); 1990 | } 1991 | --------------------------------------------------------------------------------