Skip to content

Commit ffbdc92

Browse files
loganrosenCopilot
andauthored
Bug 681635: De-duplicate values in Advanced Search (#184)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> r=justdave
1 parent 385632f commit ffbdc92

3 files changed

Lines changed: 116 additions & 46 deletions

File tree

‎docker/images/Dockerfile.perl-testsuite‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
ARG BZDB=""
1111
FROM bugzilla/bugzilla-perl-slim${BZDB}:20250925.1
1212

13+
ENV BZ_REQUIRE_NODE=1
14+
1315
WORKDIR /app
1416

1517
# Install system dependencies
@@ -19,6 +21,7 @@ RUN apt-get update && apt-get -y dist-upgrade && \
1921
cpanminus \
2022
mariadb-client \
2123
netcat-traditional \
24+
nodejs \
2225
build-essential \
2326
libapache2-mod-perl2 \
2427
libapache2-mod-perl2-dev \

‎js/productform.js‎

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -329,53 +329,24 @@ function fake_diff_array(a, b) {
329329
* @return Merged and sorted array.
330330
*/
331331
function merge_arrays(a, b, b_is_select) {
332-
var pos_a = 0;
333-
var pos_b = 0;
332+
var items = a.slice();
334333
var ret = new Array();
335-
var bitem, aitem;
336-
337-
// Iterate through both arrays and add the larger item to the return
338-
// list. Remove dupes, too. Use toLowerCase to provide
339-
// case-insensitivity.
340-
while ((pos_a < a.length) && (pos_b < b.length)) {
341-
aitem = a[pos_a];
342-
if (b_is_select)
343-
bitem = b[pos_b].value;
344-
else
345-
bitem = b[pos_b];
346-
347-
// Smaller item in list a.
348-
if (aitem.toLowerCase() < bitem.toLowerCase()) {
349-
ret[ret.length] = aitem;
350-
pos_a++;
351-
}
352-
else {
353-
// Smaller item in list b.
354-
if (aitem.toLowerCase() > bitem.toLowerCase()) {
355-
ret[ret.length] = bitem;
356-
pos_b++;
357-
}
358-
else {
359-
// List contents are equal, include both counters.
360-
ret[ret.length] = aitem;
361-
pos_a++;
362-
pos_b++;
363-
}
364-
}
365-
}
366-
367-
// Catch leftovers here. These sections are ugly code-copying.
368-
if (pos_a < a.length)
369-
for (; pos_a < a.length ; pos_a++)
370-
ret[ret.length] = a[pos_a];
371-
372-
if (pos_b < b.length) {
373-
for (; pos_b < b.length; pos_b++) {
374-
if (b_is_select)
375-
bitem = b[pos_b].value;
376-
else
377-
bitem = b[pos_b];
378-
ret[ret.length] = bitem;
334+
var i;
335+
336+
for (i = 0; i < b.length; i++)
337+
items[items.length] = b_is_select ? b[i].value : b[i];
338+
339+
items.sort(function(left, right) {
340+
left = left.toLowerCase();
341+
right = right.toLowerCase();
342+
return left < right ? -1 : left > right ? 1 : 0;
343+
});
344+
345+
for (i = 0; i < items.length; i++) {
346+
if (!ret.length
347+
|| items[i].toLowerCase() != ret[ret.length - 1].toLowerCase())
348+
{
349+
ret[ret.length] = items[i];
379350
}
380351
}
381352

‎t/015productform.t‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
#
5+
# This Source Code Form is "Incompatible With Secondary Licenses", as
6+
# defined by the Mozilla Public License, v. 2.0.
7+
8+
9+
##################
10+
#Bugzilla Test 15#
11+
####Productform###
12+
13+
use 5.14.0;
14+
use strict;
15+
use warnings;
16+
17+
use File::Spec;
18+
use Test::More;
19+
20+
my $node;
21+
foreach my $dir (File::Spec->path()) {
22+
foreach my $name (qw(node nodejs node.exe)) {
23+
my $path = File::Spec->catfile($dir, $name);
24+
if (-x $path && !-d $path) {
25+
$node = $path;
26+
last;
27+
}
28+
}
29+
last if $node;
30+
}
31+
32+
if (!$node && $ENV{BZ_REQUIRE_NODE}) {
33+
plan tests => 1;
34+
fail('Node.js is required to test js/productform.js');
35+
exit;
36+
}
37+
38+
plan skip_all => 'Node.js is required to test js/productform.js' if !$node;
39+
40+
my $script = <<'JS';
41+
var fs = require('fs');
42+
var vm = require('vm');
43+
44+
vm.runInThisContext(
45+
fs.readFileSync('js/productform.js', 'utf8'),
46+
{ filename: 'js/productform.js' }
47+
);
48+
49+
console.log(
50+
merge_arrays(
51+
['Trunk', '2.0'],
52+
['unspecified', 'Trunk'],
53+
false
54+
).join('\t')
55+
);
56+
console.log(
57+
merge_arrays(
58+
['Beta', 'alpha'],
59+
[{ value: 'ALPHA' }, { value: 'Release' }],
60+
true
61+
).join('\t')
62+
);
63+
JS
64+
65+
my $pid = open(my $fh, '-|', $node, '-e', $script);
66+
if (!defined $pid) {
67+
plan tests => 1;
68+
fail("could not run $node: $!");
69+
exit;
70+
}
71+
72+
my @results = <$fh>;
73+
close($fh);
74+
my $status = $?;
75+
76+
if ($status || @results != 2) {
77+
plan tests => 1;
78+
fail('js/productform.js did not produce the expected test output');
79+
diag("Node.js exit status: $status");
80+
diag("Node.js output:\n" . join('', @results));
81+
exit;
82+
}
83+
84+
chomp(@results);
85+
plan tests => 2;
86+
87+
is_deeply(
88+
[split(/\t/, $results[0])],
89+
['2.0', 'Trunk', 'unspecified'],
90+
'unsorted product values are sorted and de-duplicated'
91+
);
92+
is_deeply(
93+
[split(/\t/, $results[1])],
94+
['alpha', 'Beta', 'Release'],
95+
'select options are merged, sorted, and de-duplicated'
96+
);

0 commit comments

Comments
 (0)