File Coverage: t/08-validation.t

# File Coverage

File: | t/08-validation.t
Coverage: | 99.5%

line | stmt | bran | cond | sub | pod | time | code
--- | --- | --- | --- | --- | --- | --- | ---
1 | 1 1 1 |  |  | 1 |  | 2957 2 24 | use strict;
2 | 1 1 1 |  |  | 1 |  | 3 0 36 | use warnings;
3 |
4 | 1 1 1 |  |  | 1 |  | 249 1338 116 | use FindBin qw/$Bin/;
5 | 1 1 1 |  |  | 1 |  | 287 605 6 | use lib qq{$Bin/../lib};
6 | 1 1 1 |  |  | 1 |  | 545 83285 7 | use Test::More;
7 |
8 | 1 |  |  |  |  | 3111 | use OpenMP::Environment::Validation qw/
9 |  |  |  |  |  |  | validate_value validate_assignment assert_variable assert_environment
10 |  |  |  |  |  |  | analyze_environment validation_rules
11 | 1 1 |  |  | 1 |  | 726 3 | /;
12 |
13 |  |  |  |  |  |  | sub rejects {
14 | 58 |  |  | 58 |  | 120 | my ( $name, $value, $label, $pattern ) = @_;
15 | 58 |  |  |  |  | 65 | local $@;
16 | 58 58 |  |  |  |  | 79 119 | eval { validate_value( $name, $value ) };
17 | 58 |  |  |  |  | 169 | ok length($@), $label;
18 | 58 |  | 67 |  |  | 16346 | like $@, $pattern || qr/\Q$name\E/, qq{$label reports a useful diagnostic};
19 |  |  |  |  |  |  | }
20 |
21 | 1 |  |  |  |  | 73850 | my $rules = validation_rules();
22 | 1 1 |  |  |  |  | 3 6 | is scalar( @{ $rules->{fields} } ), 25, q{validation metadata contains every supported field};
23 | 1 1 |  |  |  |  | 341 5 | is scalar( keys %{ $rules->{validators} } ), 25, q{validation metadata contains every validator};
24 | 1 6 1 |  |  |  |  | 273 10 2 | ok grep( { $_ eq q{OMP_CANCELLATION} } @{ $rules->{normalized} } ), q{validation metadata records legacy-normalized variables};
25 | 1 15 1 |  |  |  |  | 251 18 3 | ok grep( { $_ eq q{OMP_NUM_THREADS} } @{ $rules->{assignment_validated} } ), q{validation metadata records variables validated during compatible assignment};
26 | 1 |  |  |  |  | 248 | is_deeply $rules->{whitespace_significant}, [ q{OMP_AFFINITY_FORMAT} ], q{validation metadata identifies the OpenMP whitespace-significant exception};
27 | 1 |  |  |  |  | 507 | is $rules->{profile}, q{OpenMP 5.2 + GCC 16.2/libgomp}, q{validation metadata names the selected standards/runtime profile};
28 |
29 | 1 |  |  |  |  | 269 | local $@;
30 | 1 1 |  |  |  |  | 1 3 | eval { validate_value( undef, 1 ) };
31 | 1 |  |  |  |  | 13 | like $@, qr/name is required/, q{validate_value requires a variable name};
32 | 1 1 |  |  |  |  | 459 4 | eval { validate_value( q{OMP_NOT_REAL}, 1 ) };
33 | 1 |  |  |  |  | 10 | like $@, qr/Unsupported/, q{validate_value rejects unsupported names};
34 | 1 |  |  |  |  | 455 | is validate_value( q{OMP_NUM_THREADS}, undef ), undef, q{validate_value passes undef through};
35 |
36 | 1 |  |  |  |  | 634 | is validate_assignment( q{GOMP_SPINCOUNT}, q{historical pass through} ), q{historical pass through}, q{assignment compatibility keeps formerly unvalidated values pass-through};
37 | 1 |  |  |  |  | 514 | is validate_assignment( q{OMP_CANCELLATION}, q{true} ), q{TRUE}, q{assignment validation retains legacy normalization};
38 | 1 1 |  |  |  |  | 485 5 | eval { validate_assignment( undef, 1 ) };
39 | 1 |  |  |  |  | 10 | like $@, qr/name is required/, q{validate_assignment requires a variable name};
40 | 1 1 |  |  |  |  | 454 4 | eval { validate_assignment( q{OMP_NOT_REAL}, 1 ) };
41 | 1 |  |  |  |  | 9 | like $@, qr/Unsupported/, q{validate_assignment rejects unsupported names};
42 | 1 |  |  |  |  | 490 | is validate_assignment( q{GOMP_SPINCOUNT}, undef ), undef, q{validate_assignment passes undef through};
43 |
44 | 1 |  |  |  |  | 598 | is validate_value( q{OMP_CANCELLATION}, q{true} ), q{TRUE}, q{OMP_CANCELLATION accepts true};
45 | 1 |  |  |  |  | 484 | is validate_value( q{OMP_CANCELLATION}, q{ true } ), q{TRUE}, q{OMP_CANCELLATION accepts OpenMP-permitted surrounding whitespace};
46 | 1 |  |  |  |  | 485 | rejects( q{OMP_CANCELLATION}, q{sometimes}, q{OMP_CANCELLATION rejects unknown boolean}, qr/TRUE/ );
47 | 1 |  |  |  |  | 451 | is validate_value( q{OMP_DISPLAY_ENV}, q{verbose} ), q{VERBOSE}, q{OMP_DISPLAY_ENV accepts VERBOSE};
48 | 1 |  |  |  |  | 495 | rejects( q{OMP_DISPLAY_ENV}, q{ALL}, q{OMP_DISPLAY_ENV rejects unknown display level} );
49 | 1 |  |  |  |  | 446 | is validate_value( q{OMP_DEFAULT_DEVICE}, 0 ), 0, q{OMP_DEFAULT_DEVICE accepts zero};
50 | 1 |  |  |  |  | 504 | is validate_value( q{OMP_DEFAULT_DEVICE}, q{ 0 } ), q{0}, q{OMP_DEFAULT_DEVICE ignores surrounding OpenMP whitespace in strict validation};
51 | 1 |  |  |  |  | 486 | rejects( q{OMP_DEFAULT_DEVICE}, -1, q{OMP_DEFAULT_DEVICE rejects negative values}, qr/integer/ );
52 | 1 |  |  |  |  | 448 | rejects( q{OMP_DEFAULT_DEVICE}, q{gpu0}, q{OMP_DEFAULT_DEVICE rejects non-integers}, qr/integer/ );
53 | 1 |  |  |  |  | 441 | is validate_value( q{OMP_NUM_TEAMS}, 1 ), 1, q{OMP_NUM_TEAMS accepts a positive integer};
54 | 1 |  |  |  |  | 478 | rejects( q{OMP_NUM_TEAMS}, 0, q{OMP_NUM_TEAMS rejects zero} );
55 | 1 |  |  |  |  | 482 | is validate_value( q{OMP_DYNAMIC}, q{true} ), q{true}, q{OMP_DYNAMIC accepts true without changing historical case};
56 | 1 |  |  |  |  | 476 | is validate_value( q{OMP_DYNAMIC}, 1 ), 1, q{OMP_DYNAMIC retains historical numeric true support};
57 | 1 |  |  |  |  | 478 | rejects( q{OMP_DYNAMIC}, q{maybe}, q{OMP_DYNAMIC rejects non-boolean value} );
58 | 1 |  |  |  |  | 454 | is validate_value( q{OMP_MAX_ACTIVE_LEVELS}, 1 ), 1, q{OMP_MAX_ACTIVE_LEVELS follows libgomp positive-integer rule};
59 | 1 |  |  |  |  | 481 | rejects( q{OMP_MAX_ACTIVE_LEVELS}, 0, q{OMP_MAX_ACTIVE_LEVELS applies the documented libgomp/legacy positive-integer profile even though OpenMP 5.2 permits zero} );
60 | 1 |  |  |  |  | 451 | is validate_value( q{OMP_MAX_TASK_PRIORITY}, 0 ), 0, q{OMP_MAX_TASK_PRIORITY accepts zero};
61 | 1 |  |  |  |  | 479 | rejects( q{OMP_MAX_TASK_PRIORITY}, -1, q{OMP_MAX_TASK_PRIORITY rejects negative values} );
62 | 1 |  |  |  |  | 445 | is validate_value( q{OMP_NESTED}, q{true} ), q{TRUE}, q{OMP_NESTED retains uppercase filter};
63 | 1 |  |  |  |  | 478 | is validate_value( q{OMP_NESTED}, 0 ), 0, q{OMP_NESTED retains numeric false compatibility};
64 | 1 |  |  |  |  | 480 | rejects( q{OMP_NESTED}, q{maybe}, q{OMP_NESTED rejects non-boolean value} );
65 | 1 |  |  |  |  | 448 | is validate_value( q{OMP_NUM_THREADS}, q{8, 4, 2} ), q{8, 4, 2}, q{OMP_NUM_THREADS accepts nested positive-integer lists};
66 | 1 |  |  |  |  | 480 | rejects( q{OMP_NUM_THREADS}, q{8,0,2}, q{OMP_NUM_THREADS rejects zero in a list}, qr/comma-separated/ );
67 |
68 | 1 |  |  |  |  | 445 | for my $value ( q{TRUE}, q{FALSE}, q{PRIMARY}, q{CLOSE}, q{SPREAD}, q{MASTER,CLOSE,SPREAD}, q{spread,close,primary} ) {
69 | 7 |  |  |  |  | 2905 | is validate_value( q{OMP_PROC_BIND}, $value ), $value, qq{OMP_PROC_BIND accepts $value};
70 |  |  |  |  |  |  | }
71 | 1 |  |  |  |  | 481 | rejects( q{OMP_PROC_BIND}, q{TRUE,CLOSE}, q{OMP_PROC_BIND does not mix boolean and policy-list syntax} );
72 | 1 |  |  |  |  | 449 | rejects( q{OMP_PROC_BIND}, q{NEAR}, q{OMP_PROC_BIND rejects an unknown policy} );
73 |
74 | 1 |  |  |  |  | 447 | for my $value (
75 |  |  |  |  |  |  | q{cores}, q{cores(4)}, q{vendor_places(2)}, q{{0,1,2},{3,4,5}},
76 |  |  |  |  |  |  | q{{0:4},{4:4}}, q{!{0},1:3}, q{{0}:4:2}, q{0:4:2}
77 |  |  |  |  |  |  | ) {
78 | 8 |  |  |  |  | 3475 | is validate_value( q{OMP_PLACES}, $value ), $value, qq{OMP_PLACES accepts $value};
79 |  |  |  |  |  |  | }
80 | 1 |  |  |  |  | 486 | rejects( q{OMP_PLACES}, q{}, q{OMP_PLACES rejects an empty value} );
81 | 1 |  |  |  |  | 450 | rejects( q{OMP_PLACES}, q{{0,,2}}, q{OMP_PLACES rejects an empty resource} );
82 | 1 |  |  |  |  | 452 | rejects( q{OMP_PLACES}, q{{0,2},}, q{OMP_PLACES rejects an empty place} );
83 | 1 |  |  |  |  | 450 | rejects( q{OMP_PLACES}, '{0,2}, {3', q{OMP_PLACES rejects unbalanced braces} );
84 | 1 |  |  |  |  | 450 | rejects( q{OMP_PLACES}, q{{x}}, q{OMP_PLACES rejects a nonnumeric explicit resource} );
85 | 1 |  |  |  |  | 448 | is validate_value( q{OMP_PLACES}, q{{!0,1}} ), q{{!0,1}}, q{OMP_PLACES accepts resource exclusion syntax};
86 | 1 |  |  |  |  | 212 | rejects( q{OMP_PLACES}, q{@}, q{OMP_PLACES rejects a malformed explicit place} );
87 | 1 |  |  |  |  | 193 | rejects( q{OMP_PLACES}, '0}', q{OMP_PLACES rejects an unmatched closing brace} );
88 | 1 |  |  |  |  | 190 | rejects( q{OMP_PLACES}, q{{}}, q{OMP_PLACES rejects an empty explicit resource list} );
89 | 1 |  |  |  |  | 197 | rejects( q{OMP_PLACES}, q{0:0}, q{OMP_PLACES rejects a zero-length place interval} );
90 |
91 | 1 |  |  |  |  | 192 | for my $value ( q{1}, q{1024}, q{64M}, q{2G}, q{4096K} ) {
92 | 5 |  |  |  |  | 831 | is validate_value( q{OMP_STACKSIZE}, $value ), $value, qq{OMP_STACKSIZE accepts $value};
93 |  |  |  |  |  |  | }
94 | 1 |  |  |  |  | 205 | rejects( q{OMP_STACKSIZE}, q{0}, q{OMP_STACKSIZE rejects zero} );
95 | 1 |  |  |  |  | 194 | rejects( q{OMP_STACKSIZE}, q{4T}, q{OMP_STACKSIZE rejects an unsupported unit} );
96 |
97 | 1 |  |  |  |  | 191 | for my $value ( q{static}, q{dynamic,4}, q{guided,8}, q{auto}, q{monotonic:static}, q{nonmonotonic:dynamic,4} ) {
98 | 6 |  |  |  |  | 1032 | is validate_value( q{OMP_SCHEDULE}, $value ), $value, qq{OMP_SCHEDULE accepts $value};
99 |  |  |  |  |  |  | }
100 | 1 |  |  |  |  | 207 | rejects( q{OMP_SCHEDULE}, q{banana}, q{OMP_SCHEDULE rejects an unknown kind} );
101 | 1 |  |  |  |  | 196 | rejects( q{OMP_SCHEDULE}, q{dynamic,0}, q{OMP_SCHEDULE rejects zero chunk size} );
102 | 1 |  |  |  |  | 200 | rejects( q{OMP_SCHEDULE}, q{random:dynamic,4}, q{OMP_SCHEDULE rejects an unknown modifier} );
103 | 1 |  |  |  |  | 190 | is validate_value( q{OMP_SCHEDULE}, q{ dynamic,4 } ), q{dynamic,4}, q{OMP_SCHEDULE ignores surrounding OpenMP whitespace};
104 |
105 | 1 |  |  |  |  | 208 | is validate_value( q{OMP_TARGET_OFFLOAD}, q{mandatory} ), q{MANDATORY}, q{OMP_TARGET_OFFLOAD normalizes a standard value};
106 | 1 |  |  |  |  | 205 | rejects( q{OMP_TARGET_OFFLOAD}, q{FORCE}, q{OMP_TARGET_OFFLOAD rejects an unknown mode} );
107 | 1 |  |  |  |  | 204 | is validate_value( q{OMP_THREAD_LIMIT}, 1 ), 1, q{OMP_THREAD_LIMIT accepts positive integer};
108 | 1 |  |  |  |  | 206 | rejects( q{OMP_THREAD_LIMIT}, 0, q{OMP_THREAD_LIMIT rejects zero} );
109 | 1 |  |  |  |  | 204 | is validate_value( q{OMP_WAIT_POLICY}, q{active} ), q{ACTIVE}, q{OMP_WAIT_POLICY accepts ACTIVE};
110 | 1 |  |  |  |  | 205 | rejects( q{OMP_WAIT_POLICY}, q{SLEEP}, q{OMP_WAIT_POLICY rejects unknown policy} );
111 |
112 | 1 |  |  |  |  | 189 | for my $value ( q{0}, q{0 3 1-2 4-15:2}, q{0,2,4-8:2} ) {
113 | 3 |  |  |  |  | 417 | is validate_value( q{GOMP_CPU_AFFINITY}, $value ), $value, qq{GOMP_CPU_AFFINITY accepts $value};
114 |  |  |  |  |  |  | }
115 | 1 |  |  |  |  | 207 | rejects( q{GOMP_CPU_AFFINITY}, q{cpu0}, q{GOMP_CPU_AFFINITY rejects symbolic CPUs} );
116 | 1 |  |  |  |  | 191 | rejects( q{GOMP_CPU_AFFINITY}, q{4-8:0}, q{GOMP_CPU_AFFINITY rejects zero stride} );
117 | 1 |  |  |  |  | 192 | is validate_value( q{GOMP_DEBUG}, 0 ), 0, q{GOMP_DEBUG accepts zero};
118 | 1 |  |  |  |  | 207 | is validate_value( q{GOMP_DEBUG}, 1 ), 1, q{GOMP_DEBUG accepts one};
119 | 1 |  |  |  |  | 204 | rejects( q{GOMP_DEBUG}, 2, q{GOMP_DEBUG rejects values outside 0/1} );
120 | 1 |  |  |  |  | 192 | is validate_value( q{GOMP_STACKSIZE}, q{1024} ), q{1024}, q{GOMP_STACKSIZE accepts the GNU-native numeric-kilobyte form};
121 | 1 |  |  |  |  | 206 | is validate_value( q{GOMP_STACKSIZE}, q{1024G} ), q{1024G}, q{GOMP_STACKSIZE retains the documented OpenMP::Environment unit-suffix compatibility extension};
122 | 1 |  |  |  |  | 205 | is validate_assignment( q{GOMP_STACKSIZE}, q{1024G} ), q{1024G}, q{GOMP_STACKSIZE assignment remains pass-through for pre-1.5 compatibility};
123 | 1 |  |  |  |  | 204 | rejects( q{GOMP_STACKSIZE}, 0, q{GOMP_STACKSIZE rejects zero} );
124 | 1 |  |  |  |  | 205 | for my $value ( q{0}, q{300000}, q{4k}, q{30M}, q{2G}, q{1T}, q{INFINITE}, q{INFINITY} ) {
125 | 8 |  |  |  |  | 1440 | is validate_value( q{GOMP_SPINCOUNT}, $value ), $value, qq{GOMP_SPINCOUNT accepts $value};
126 |  |  |  |  |  |  | }
127 | 1 |  |  |  |  | 221 | rejects( q{GOMP_SPINCOUNT}, q{4m}, q{GOMP_SPINCOUNT preserves documented suffix case} );
128 | 1 |  |  |  |  | 192 | rejects( q{GOMP_SPINCOUNT}, q{forever}, q{GOMP_SPINCOUNT rejects unknown words} );
129 | 1 |  |  |  |  | 194 | is validate_value( q{GOMP_RTEMS_THREAD_POOLS}, q{1@WRK0:3$4@WRK1} ), q{1@WRK0:3$4@WRK1}, q{GOMP_RTEMS_THREAD_POOLS accepts libgomp example grammar};
130 | 1 |  |  |  |  | 208 | rejects( q{GOMP_RTEMS_THREAD_POOLS}, q{0@WRK0}, q{GOMP_RTEMS_THREAD_POOLS rejects zero pool count} );
131 | 1 |  |  |  |  | 190 | rejects( q{GOMP_RTEMS_THREAD_POOLS}, q{1WRK0}, q{GOMP_RTEMS_THREAD_POOLS requires scheduler separator} );
132 | 1 |  |  |  |  | 190 | is validate_value( q{OMP_TEAMS_THREAD_LIMIT}, 1 ), 1, q{OMP_TEAMS_THREAD_LIMIT accepts positive integer};
133 | 1 |  |  |  |  | 232 | rejects( q{OMP_TEAMS_THREAD_LIMIT}, 0, q{OMP_TEAMS_THREAD_LIMIT rejects zero} );
134 |
135 | 1 |  |  |  |  | 192 | for my $value (
136 |  |  |  |  |  |  | q{omp_default_mem_alloc}, q{omp_high_bw_mem_alloc}, q{omp_default_mem_space},
137 |  |  |  |  |  |  | q{omp_large_cap_mem_space:alignment=16,pinned=true},
138 |  |  |  |  |  |  | q{omp_low_lat_mem_space:sync_hint=private,access=thread,pool_size=1024,partition=nearest},
139 |  |  |  |  |  |  | q{ompx_gnu_pinned_mem_alloc}, q{ompx_gnu_managed_mem_alloc},
140 |  |  |  |  |  |  | q{ompx_gnu_managed_mem_space}
141 |  |  |  |  |  |  | ) {
142 | 8 |  |  |  |  | 1446 | is validate_value( q{OMP_ALLOCATOR}, $value ), $value, qq{OMP_ALLOCATOR accepts $value};
143 |  |  |  |  |  |  | }
144 | 1 |  |  |  |  | 206 | rejects( q{OMP_ALLOCATOR}, q{not_an_allocator}, q{OMP_ALLOCATOR rejects an unknown allocator} );
145 | 1 |  |  |  |  | 192 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:}, q{OMP_ALLOCATOR rejects an empty trait list} );
146 | 1 |  |  |  |  | 192 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:alignment=3}, q{OMP_ALLOCATOR requires power-of-two alignment} );
147 | 1 |  |  |  |  | 195 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:alignment=foo}, q{OMP_ALLOCATOR requires numeric alignment} );
148 | 1 |  |  |  |  | 193 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:pool_size=0}, q{OMP_ALLOCATOR requires positive pool size} );
149 | 1 |  |  |  |  | 193 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:pinned=maybe}, q{OMP_ALLOCATOR validates boolean traits} );
150 | 1 |  |  |  |  | 190 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:partition=random}, q{OMP_ALLOCATOR validates partition values} );
151 | 1 |  |  |  |  | 191 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:access=process}, q{OMP_ALLOCATOR validates access values} );
152 | 1 |  |  |  |  | 191 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:sync_hint=often}, q{OMP_ALLOCATOR validates sync_hint values} );
153 | 1 |  |  |  |  | 206 | is validate_value( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fallback=allocator_fb} ), q{omp_low_lat_mem_space:fallback=allocator_fb}, q{OMP_ALLOCATOR accepts allocator_fb because libgomp explicitly lists it as an allowed fallback token};
154 | 1 |  |  |  |  | 205 | is validate_value( q{OMP_ALLOCATOR}, q{OMP_HIGH_BW_MEM_ALLOC} ), q{OMP_HIGH_BW_MEM_ALLOC}, q{OMP_ALLOCATOR values are case-insensitive under the general OpenMP environment rule};
155 | 1 |  |  |  |  | 207 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fb_data=not_an_allocator}, q{OMP_ALLOCATOR validates fb_data allocator names before applying the libgomp restriction} );
156 | 1 |  |  |  |  | 192 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fb_data=omp_default_mem_alloc}, q{OMP_ALLOCATOR rejects OpenMP fb_data because libgomp documents it as unsupported} );
157 | 1 |  |  |  |  | 191 | is validate_value( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fallback=default_mem_fb} ), q{omp_low_lat_mem_space:fallback=default_mem_fb}, q{OMP_ALLOCATOR accepts non-handle fallback choices};
158 | 1 |  |  |  |  | 206 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:alignment=16,alignment=32}, q{OMP_ALLOCATOR rejects duplicate traits} );
159 | 1 |  |  |  |  | 212 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:mystery=yes}, q{OMP_ALLOCATOR rejects unknown traits} );
160 | 1 |  |  |  |  | 190 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:pinned}, q{OMP_ALLOCATOR rejects malformed traits} );
161 |
162 | 1 |  |  |  |  | 190 | for my $value ( q{literal text}, q{thread %n affinity %A}, q{level %4L thread %0.2n}, q{host %.12{host}}, q{%% %n}, q{%{thread_num}}, q{vendor %x} ) {
163 | 7 |  |  |  |  | 1255 | is validate_value( q{OMP_AFFINITY_FORMAT}, $value ), $value, qq{OMP_AFFINITY_FORMAT accepts $value};
164 |  |  |  |  |  |  | }
165 | 1 |  |  |  |  | 208 | is validate_value( q{OMP_AFFINITY_FORMAT}, q{ %n } ), q{ %n }, q{OMP_AFFINITY_FORMAT preserves significant leading and trailing whitespace};
166 | 1 |  |  |  |  | 206 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %}, q{OMP_AFFINITY_FORMAT rejects a trailing percent} );
167 | 1 |  |  |  |  | 192 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %0n}, q{OMP_AFFINITY_FORMAT rejects malformed width syntax} );
168 | 1 |  |  |  |  | 192 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %.0L}, q{OMP_AFFINITY_FORMAT rejects a zero minimum width} );
169 | 1 |  |  |  |  | 214 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %0.0L}, q{OMP_AFFINITY_FORMAT rejects a zero-padded zero minimum width} );
170 | 1 |  |  |  |  | 191 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %{bad-name}}, q{OMP_AFFINITY_FORMAT rejects malformed long field name} );
171 | 1 |  |  |  |  | 189 | is validate_value( q{OMP_DISPLAY_AFFINITY}, q{false} ), q{FALSE}, q{OMP_DISPLAY_AFFINITY accepts and normalizes false};
172 | 1 |  |  |  |  | 206 | rejects( q{OMP_DISPLAY_AFFINITY}, q{sometimes}, q{OMP_DISPLAY_AFFINITY rejects non-boolean value} );
173 |
174 | 1 |  |  |  |  | 190 | local $@;
175 | 1 1 |  |  |  |  | 1 2 | eval { assert_variable( [], q{OMP_NUM_THREADS} ) };
176 | 1 |  |  |  |  | 4 | like $@, qr/hash reference/, q{assert_variable requires a hash reference};
177 | 1 1 |  |  |  |  | 192 2 | eval { assert_variable( {}, q{OMP_NOT_REAL} ) };
178 | 1 |  |  |  |  | 4 | like $@, qr/Unsupported/, q{assert_variable rejects unknown names};
179 | 1 |  |  |  |  | 196 | my %one = ( OMP_NUM_THREADS => q{4,2} );
180 | 1 |  |  |  |  | 2 | ok assert_variable( \%one, q{OMP_NUM_THREADS} ), q{assert_variable validates a set variable};
181 | 1 |  |  |  |  | 219 | my %unset;
182 | 1 |  |  |  |  | 3 | ok assert_variable( \%unset, q{OMP_NUM_THREADS} ), q{assert_variable accepts an unset variable};
183 | 1 |  |  |  |  | 209 | my %unrelated_conflict = ( OMP_NESTED => q{FALSE}, OMP_MAX_ACTIVE_LEVELS => 4, OMP_SCHEDULE => q{static} );
184 | 1 |  |  |  |  | 3 | ok assert_variable( \%unrelated_conflict, q{OMP_SCHEDULE} ), q{assert_variable ignores a cross-variable conflict unrelated to the requested variable};
185 |
186 | 1 |  |  |  |  | 197 | local $@;
187 | 1 1 |  |  |  |  | 1 2 | eval { assert_environment([]) };
188 | 1 |  |  |  |  | 4 | like $@, qr/hash reference/, q{assert_environment requires a hash reference};
189 | 1 |  |  |  |  | 195 | my %strict = ( OMP_CANCELLATION => q{true}, OMP_SCHEDULE => q{guided,4} );
190 | 1 |  |  |  |  | 3 | ok assert_environment( \%strict ), q{assert_environment validates a portable environment};
191 | 1 |  |  |  |  | 198 | is $strict{OMP_CANCELLATION}, q{TRUE}, q{assert_environment writes normalized values back};
192 | 1 |  |  |  |  | 210 | my %conflict = ( OMP_NESTED => q{FALSE}, OMP_MAX_ACTIVE_LEVELS => 4 );
193 | 1 1 |  |  |  |  | 1 2 | eval { assert_environment( \%conflict ) };
194 | 1 |  |  |  |  | 3 | like $@, qr/conflict/, q{assert_environment rejects an explicit OpenMP implementation-defined conflict};
195 |
196 | 1 |  |  |  |  | 194 | local $@;
197 | 1 1 |  |  |  |  | 1 2 | eval { analyze_environment([]) };
198 | 1 |  |  |  |  | 6 | like $@, qr/hash reference/, q{analyze_environment requires a hash reference};
199 | 1 |  |  |  |  | 199 | my %analysis_env = (
200 |  |  |  |  |  |  | OMP_NESTED => q{TRUE},
201 |  |  |  |  |  |  | OMP_MAX_ACTIVE_LEVELS => 4,
202 |  |  |  |  |  |  | OMP_NUM_THREADS => q{8,4},
203 |  |  |  |  |  |  | OMP_PROC_BIND => q{SPREAD,CLOSE},
204 |  |  |  |  |  |  | GOMP_CPU_AFFINITY => q{0-7},
205 |  |  |  |  |  |  | OMP_PLACES => q{cores},
206 |  |  |  |  |  |  | OMP_DEFAULT_DEVICE => 7,
207 |  |  |  |  |  |  | OMP_STACKSIZE => q{64G},
208 |  |  |  |  |  |  | OMP_ALLOCATOR => q{omp_high_bw_mem_alloc},
209 |  |  |  |  |  |  | OMP_THREAD_LIMIT => 1024,
210 |  |  |  |  |  |  | GOMP_RTEMS_THREAD_POOLS => q{1@WRK0},
211 |  |  |  |  |  |  | );
212 | 1 |  |  |  |  | 3 | my $analysis = analyze_environment( \%analysis_env );
213 | 1 |  |  |  |  | 5 | ok $analysis->{valid}, q{runtime-dependent but syntactically valid environment remains valid};
214 | 1 1 |  |  |  |  | 204 4 | ok @{ $analysis->{runtime_dependent} } >= 8, q{analysis identifies runtime-dependent settings without probing the system};
215 | 1 1 |  |  |  |  | 194 11 | ok grep( /OMP_PROC_BIND takes precedence/, @{ $analysis->{notes} } ), q{analysis documents GNU precedence relationship};
216 | 1 1 |  |  |  |  | 193 5 | ok grep( /OMP_NESTED has no effect/, @{ $analysis->{notes} } ), q{analysis documents nonconflicting OMP_NESTED relationship};
217 | 1 1 |  |  |  |  | 189 5 | ok grep( /max-active-levels-var/, @{ $analysis->{notes} } ), q{analysis documents nested list effect on max-active-levels-var};
218 |
219 | 1 |  |  |  |  | 191 | my $bad_analysis = analyze_environment( { OMP_SCHEDULE => q{banana} } );
220 | 1 |  |  |  |  | 4 | ok !$bad_analysis->{valid}, q{analysis marks malformed environment invalid};
221 | 1 1 |  |  |  |  | 204 2 | is scalar( @{ $bad_analysis->{errors} } ), 1, q{analysis reports malformed value as an error};
222 | 1 |  |  |  |  | 209 | my $conflict_analysis = analyze_environment( { OMP_NESTED => q{false}, OMP_MAX_ACTIVE_LEVELS => 2 } );
223 | 1 |  |  |  |  | 4 | ok !$conflict_analysis->{valid}, q{analysis marks cross-variable conflict invalid};
224 | 1 |  |  |  |  | 196 | is $conflict_analysis->{conflicts}->[0]->{class}, q{implementation-defined}, q{analysis classifies the OpenMP conflict};
225 |
226 | 1 |  |  |  |  | 209 | done_testing;
227 |