Skip to content

Commit 7fd67b4

Browse files
authored
Merge pull request #153 from os-checker/feat/route-query-on-testcases
feat(testcases): add route query
2 parents afa2e58 + d425de9 commit 7fd67b4

File tree

2 files changed

+193
-122
lines changed

2 files changed

+193
-122
lines changed

os-checks/pages/testcases.vue

Lines changed: 64 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@
9898
import type { DataTableSortMeta } from 'primevue/datatable';
9999
import { FilterMatchMode } from '@primevue/core/api';
100100
import type { PkgInfo } from '~/shared/info';
101-
import { cloneDeep, uniq } from 'es-toolkit/compat';
101+
import type { TestResult, Selection, Options } from '~/shared/testcases';
102+
import { defaultOptions, applySelection, testcasesToOptions, summariesToTestResult } from '~/shared/testcases';
102103
103104
useHead({ title: 'Test Cases' });
104105
@@ -126,74 +127,17 @@ watch(selectedTest, sel => dialogShow.value = sel ? true : false);
126127
githubFetch<PkgInfo[]>({
127128
path: "plugin/cargo/info/summaries.json"
128129
}).then(val => {
129-
testcases.value = summariesToTestResult(val);
130-
testcasesFiltered.value = cloneDeep(testcases.value);
130+
const tc = summariesToTestResult(val);
131+
testcases.value = tc;
132+
testcasesFiltered.value = applySelection(tc, selected);
131133
});
132134
133-
type TestResult = {
134-
idx: number,
135-
user: string,
136-
repo: string,
137-
pkg: string,
138-
bin: string,
139-
kind: string,
140-
name: string,
141-
test_pass: string,
142-
test_duration_ms: number | null,
143-
test_error: string | null,
144-
miri_pass: string,
145-
miri_output: string | null,
146-
miri_timeout: string,
147-
};
148-
149-
function summariesToTestResult(pkg_info: PkgInfo[]): TestResult[] {
150-
let result: TestResult[] = [];
151-
let idx = 0;
152-
153-
for (const info of pkg_info) {
154-
for (const [pkg, value] of Object.entries(info.pkgs)) {
155-
for (const test of value.testcases?.tests || []) {
156-
for (const testcase of test.testcases) {
157-
result.push({
158-
idx: idx++,
159-
user: info.user,
160-
repo: info.repo,
161-
pkg,
162-
bin: test.binary_name,
163-
kind: test.kind,
164-
name: testcase.name,
165-
test_pass: testcase.status === "ok" ? "" : (testcase.status === "failed" ? "" : ""),
166-
test_duration_ms: testcase.duration_ms,
167-
test_error: testcase.error,
168-
miri_pass: testcase.miri_pass ? "" : "",
169-
miri_output: testcase.miri_output,
170-
miri_timeout: testcase.miri_timeout ? "💥" : "",
171-
});
172-
}
173-
}
174-
}
175-
}
176-
177-
return result;
178-
}
179-
180135
function sortsChanged(meta?: DataTableSortMeta[] | null) {
181136
if (meta) {
182137
selected.sorts = meta;
183138
}
184139
}
185-
186-
const selected = reactive<{
187-
user: string | null,
188-
repo: string | null,
189-
pkg: string | null,
190-
kind: string | null,
191-
test_pass: string | null,
192-
miri_pass: string | null,
193-
miri_timeout: string | null,
194-
text: any,
195-
sorts: DataTableSortMeta[],
196-
}>({
140+
const selected = reactive<Selection>({
197141
user: null,
198142
repo: null,
199143
pkg: null,
@@ -205,73 +149,71 @@ const selected = reactive<{
205149
sorts: [],
206150
});
207151
208-
type Options = {
209-
user: string[],
210-
repo: string[],
211-
pkg: string[],
212-
kind: string[],
213-
test_pass: string[],
214-
miri_pass: string[],
215-
miri_timeout: string[],
216-
};
217-
function defaultOptions(): Options {
218-
return {
219-
user: [],
220-
repo: [],
221-
pkg: [],
222-
kind: [],
223-
test_pass: [],
224-
miri_pass: [],
225-
miri_timeout: [],
226-
};
227-
}
228152
const options = reactive<{ val: Options }>({ val: defaultOptions() });
229153
230154
// init options
231155
watch(testcases, tc => options.val = testcasesToOptions(tc));
232156
233157
// update table when filter selection changes
234-
watch(
235-
selected,
236-
({ user, repo, pkg, kind, test_pass, miri_pass, miri_timeout }) => {
237-
// for simplicity, the data of testcases are supposed to remain unchanged
238-
const chosen_testcases = testcases.value.filter(test => {
239-
let chosen = true;
240-
if (user) chosen &&= test.user === user;
241-
if (repo) chosen &&= test.repo === repo;
242-
if (pkg) chosen &&= test.pkg === pkg;
243-
if (kind) chosen &&= test.kind === repo;
244-
if (test_pass) chosen &&= test.test_pass === test_pass;
245-
if (miri_pass) chosen &&= test.miri_pass === miri_pass;
246-
if (miri_timeout || miri_timeout === "") chosen &&= test.miri_timeout === miri_timeout;
247-
return chosen;
248-
});
249-
testcasesFiltered.value = chosen_testcases.map((tc, idx) => {
250-
tc.idx = idx;
251-
return tc;
158+
watch(selected, sel => testcasesFiltered.value = applySelection(testcases.value, sel));
159+
160+
// ******************* route query *******************
161+
const route = useRoute();
162+
function updateFilter(query: {
163+
user?: string,
164+
repo?: string,
165+
pkg?: string,
166+
kind?: string,
167+
test_pass?: string,
168+
miri_pass?: string,
169+
miri_timeout?: string,
170+
text?: string,
171+
sorts?: string,
172+
}) {
173+
const { user, repo, pkg, kind, test_pass, miri_pass, miri_timeout, text, sorts } = query;
174+
175+
// only support single value for each param
176+
// FIXME: empty string will not handled
177+
if (user) selected.user = decodeURIComponent(user);
178+
if (repo) selected.repo = decodeURIComponent(repo);
179+
if (pkg) selected.pkg = decodeURIComponent(pkg);
180+
if (kind) selected.kind = decodeURIComponent(kind);
181+
if (test_pass) selected.test_pass = decodeURIComponent(test_pass);
182+
if (miri_pass) selected.miri_pass = decodeURIComponent(miri_pass);
183+
if (miri_timeout) selected.miri_timeout = decodeURIComponent(miri_timeout);
184+
if (text) selected.text.global.value = decodeURIComponent(text);
185+
186+
if (sorts) {
187+
const args = decodeURIComponent(sorts).split(",");
188+
//@ts-ignore
189+
selected.sorts = args.map(arg => {
190+
let [field, order] = arg.split("=");
191+
return { field, order: parseInt(order) };
252192
});
253-
// options.val = testcasesToOptions(chosen_testcases);
254-
});
255-
256-
function testcasesToOptions(tc: TestResult[]): Options {
257-
let opts = defaultOptions();
258-
for (const test of tc) {
259-
opts.user.push(test.user);
260-
opts.repo.push(test.repo);
261-
opts.pkg.push(test.pkg);
262-
opts.kind.push(test.kind);
263-
opts.test_pass.push(test.test_pass);
264-
opts.miri_pass.push(test.miri_pass);
265-
opts.miri_timeout.push(test.miri_timeout);
266193
}
267-
268-
opts.user = uniq(opts.user).sort();
269-
opts.repo = uniq(opts.repo).sort();
270-
opts.pkg = uniq(opts.pkg).sort();
271-
opts.kind = uniq(opts.kind).sort();
272-
opts.test_pass = uniq(opts.test_pass).sort();
273-
opts.miri_pass = uniq(opts.miri_pass).sort();
274-
opts.miri_timeout = uniq(opts.miri_timeout).sort();
275-
return opts;
276194
}
195+
updateFilter(route.query);
196+
197+
const router = useRouter();
198+
watch(selected, sel => {
199+
const { user, repo, pkg, kind, test_pass, miri_pass, miri_timeout, text, sorts } = sel;
200+
201+
let query: any = {};
202+
203+
if (user) query.user = encodeURIComponent(user);
204+
if (repo) query.repo = encodeURIComponent(repo);
205+
if (pkg) query.pkg = encodeURIComponent(pkg);
206+
if (kind) query.kind = encodeURIComponent(kind);
207+
if (test_pass) query.test_pass = encodeURIComponent(test_pass);
208+
if (miri_pass) query.miri_pass = encodeURIComponent(miri_pass);
209+
if (miri_timeout) query.miri_timeout = encodeURIComponent(miri_timeout);
210+
if (text.global.value) query.text = encodeURIComponent(text.global.value);
211+
212+
if (sorts.length !== 0) {
213+
const args = sorts.map(({ field, order }) => order ? `${field}=${order}` : null);
214+
query.sorts = encodeURIComponent(args.filter(x => x).join(","));
215+
}
216+
217+
router.push({ path: route.path, query });
218+
});
277219
</script>

os-checks/shared/testcases.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import type { DataTableSortMeta } from 'primevue/datatable';
2+
import { uniq } from 'es-toolkit/compat';
3+
import type { PkgInfo } from './info';
4+
5+
export type TestResult = {
6+
idx: number,
7+
user: string,
8+
repo: string,
9+
pkg: string,
10+
bin: string,
11+
kind: string,
12+
name: string,
13+
test_pass: string,
14+
test_duration_ms: number | null,
15+
test_error: string | null,
16+
miri_pass: string,
17+
miri_output: string | null,
18+
miri_timeout: string,
19+
};
20+
21+
export type Selection = {
22+
user: string | null,
23+
repo: string | null,
24+
pkg: string | null,
25+
kind: string | null,
26+
test_pass: string | null,
27+
miri_pass: string | null,
28+
miri_timeout: string | null,
29+
text: any,
30+
sorts: DataTableSortMeta[],
31+
};
32+
33+
/** Called when testcases are fetched or selection is updated */
34+
export function applySelection(
35+
testcases: TestResult[],
36+
{ user, repo, pkg, kind, test_pass, miri_pass, miri_timeout }: Selection
37+
): TestResult[] {
38+
// for simplicity, the data of testcases are supposed to remain unchanged
39+
const chosen_testcases = testcases.filter(test => {
40+
let chosen = true;
41+
if (user) chosen &&= test.user === user;
42+
if (repo) chosen &&= test.repo === repo;
43+
if (pkg) chosen &&= test.pkg === pkg;
44+
if (kind) chosen &&= test.kind === repo;
45+
if (test_pass) chosen &&= test.test_pass === test_pass;
46+
if (miri_pass) chosen &&= test.miri_pass === miri_pass;
47+
if (miri_timeout || miri_timeout === "") chosen &&= test.miri_timeout === miri_timeout;
48+
return chosen;
49+
});
50+
return chosen_testcases.map((tc, idx) => {
51+
tc.idx = idx;
52+
return tc;
53+
});
54+
}
55+
56+
export type Options = {
57+
user: string[],
58+
repo: string[],
59+
pkg: string[],
60+
kind: string[],
61+
test_pass: string[],
62+
miri_pass: string[],
63+
miri_timeout: string[],
64+
};
65+
66+
export function defaultOptions(): Options {
67+
return {
68+
user: [],
69+
repo: [],
70+
pkg: [],
71+
kind: [],
72+
test_pass: [],
73+
miri_pass: [],
74+
miri_timeout: [],
75+
};
76+
}
77+
78+
export function testcasesToOptions(tc: TestResult[]): Options {
79+
let opts = defaultOptions();
80+
for (const test of tc) {
81+
opts.user.push(test.user);
82+
opts.repo.push(test.repo);
83+
opts.pkg.push(test.pkg);
84+
opts.kind.push(test.kind);
85+
opts.test_pass.push(test.test_pass);
86+
opts.miri_pass.push(test.miri_pass);
87+
opts.miri_timeout.push(test.miri_timeout);
88+
}
89+
90+
opts.user = uniq(opts.user).sort();
91+
opts.repo = uniq(opts.repo).sort();
92+
opts.pkg = uniq(opts.pkg).sort();
93+
opts.kind = uniq(opts.kind).sort();
94+
opts.test_pass = uniq(opts.test_pass).sort();
95+
opts.miri_pass = uniq(opts.miri_pass).sort();
96+
opts.miri_timeout = uniq(opts.miri_timeout).sort();
97+
return opts;
98+
}
99+
100+
export function summariesToTestResult(pkg_info: PkgInfo[]): TestResult[] {
101+
let result: TestResult[] = [];
102+
let idx = 0;
103+
104+
for (const info of pkg_info) {
105+
for (const [pkg, value] of Object.entries(info.pkgs)) {
106+
for (const test of value.testcases?.tests || []) {
107+
for (const testcase of test.testcases) {
108+
result.push({
109+
idx: idx++,
110+
user: info.user,
111+
repo: info.repo,
112+
pkg,
113+
bin: test.binary_name,
114+
kind: test.kind,
115+
name: testcase.name,
116+
test_pass: testcase.status === "ok" ? "✅" : (testcase.status === "failed" ? "❌" : ""),
117+
test_duration_ms: testcase.duration_ms,
118+
test_error: testcase.error,
119+
miri_pass: testcase.miri_pass ? "✅" : "❌",
120+
miri_output: testcase.miri_output,
121+
miri_timeout: testcase.miri_timeout ? "💥" : "",
122+
});
123+
}
124+
}
125+
}
126+
}
127+
128+
return result;
129+
}

0 commit comments

Comments
 (0)