feat(frontend): enable problem-scoped Python and Java submissions
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { test } from 'node:test'
|
||||
import type { components } from '../src/api/generated/schema'
|
||||
import {
|
||||
languageCapability,
|
||||
preparationName,
|
||||
preparingStatus,
|
||||
} from '../src/composables/judgingLanguage.ts'
|
||||
|
||||
const limits: components['schemas']['RunLimits'] = {
|
||||
cpu_time_us: 1_000_000,
|
||||
wall_time_us: 3_000_000,
|
||||
memory_bytes: 67_108_864,
|
||||
file_bytes: 16_777_216,
|
||||
open_files: 64,
|
||||
processes: 8,
|
||||
stack_bytes: 8_388_608,
|
||||
stderr_bytes: 1_048_576,
|
||||
stdout_bytes: 1_048_576,
|
||||
workdir_bytes: 67_108_864,
|
||||
}
|
||||
const python: components['schemas']['PublicLanguageConfiguration'] = {
|
||||
language: 'python313',
|
||||
runtime_version: '3.13.16',
|
||||
source_name: 'main.py',
|
||||
entrypoint: 'main.py',
|
||||
preparation_kind: 'syntax_check',
|
||||
compile_limits: limits,
|
||||
run_limits: { ...limits, cpu_time_us: 2_000_000 },
|
||||
job_wall_time_us: 12_000_000,
|
||||
}
|
||||
const java: components['schemas']['PublicLanguageConfiguration'] = {
|
||||
language: 'java21',
|
||||
runtime_version: '21.0.12.1+1-LTS',
|
||||
source_name: 'Main.java',
|
||||
entrypoint: 'Main',
|
||||
preparation_kind: 'compile',
|
||||
compile_limits: limits,
|
||||
run_limits: { ...limits, memory_bytes: 134_217_728 },
|
||||
job_wall_time_us: 12_000_000,
|
||||
}
|
||||
type Problem = Parameters<typeof languageCapability>[0]
|
||||
|
||||
test('server capability controls managed submission and the selected version/budget; legacy C stays supported', () => {
|
||||
const legacy: Problem = {
|
||||
languages: ['c17', 'cpp20'],
|
||||
language_configurations: [],
|
||||
run_limits: limits,
|
||||
}
|
||||
assert.equal(languageCapability(legacy, 'c')?.wire, 'c17')
|
||||
assert.equal(languageCapability(legacy, 'cpp')?.runLimits, limits)
|
||||
assert.equal(languageCapability(legacy, 'python'), null)
|
||||
assert.equal(languageCapability(legacy, 'java'), null)
|
||||
assert.equal(languageCapability(legacy, 'rust'), null)
|
||||
const current: Problem = {
|
||||
languages: ['python313', 'java21'],
|
||||
language_configurations: [python, java],
|
||||
run_limits: null,
|
||||
}
|
||||
assert.equal(
|
||||
languageCapability(current, 'python')?.configuration?.runtime_version,
|
||||
python.runtime_version,
|
||||
)
|
||||
assert.equal(languageCapability(current, 'python')?.runLimits.cpu_time_us, 2_000_000)
|
||||
assert.equal(languageCapability(current, 'java')?.runLimits.memory_bytes, 134_217_728)
|
||||
assert.equal(languageCapability(current, 'java')?.configuration?.entrypoint, 'Main')
|
||||
assert.equal(languageCapability(current, 'c'), null)
|
||||
assert.equal(languageCapability(null, 'python'), null)
|
||||
})
|
||||
|
||||
test('managed language with absent or invalid fixed entry capability cannot inherit legacy budget', () => {
|
||||
const missing: Problem = {
|
||||
languages: ['python313', 'java21'],
|
||||
language_configurations: [],
|
||||
run_limits: limits,
|
||||
}
|
||||
assert.equal(languageCapability(missing, 'python'), null)
|
||||
assert.equal(languageCapability(missing, 'java'), null)
|
||||
for (const invalid of [
|
||||
{ ...python, preparation_kind: 'compile' as const },
|
||||
{ ...python, source_name: 'main.pyc' },
|
||||
{ ...java, entrypoint: 'Other' },
|
||||
{ ...java, source_name: 'package/Main.java' },
|
||||
{ ...java, runtime_version: '' },
|
||||
]) {
|
||||
const problem: Problem = {
|
||||
languages: [invalid.language],
|
||||
language_configurations: [invalid],
|
||||
run_limits: limits,
|
||||
}
|
||||
assert.equal(
|
||||
languageCapability(problem, invalid.language === 'python313' ? 'python' : 'java'),
|
||||
null,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
test('Python preparation is displayed as syntax checking while Java and old C/C++ compile', () => {
|
||||
assert.equal(preparingStatus('python313'), '正在检查语法')
|
||||
assert.equal(preparationName('python313'), '语法检查')
|
||||
for (const language of ['c17', 'cpp20', 'java21'] as const) {
|
||||
assert.equal(preparingStatus(language), '正在编译')
|
||||
assert.equal(preparationName(language), '编译')
|
||||
}
|
||||
})
|
||||
@@ -22,13 +22,45 @@ const flush = async () => {
|
||||
await new Promise<void>((resolve) => setImmediate(resolve))
|
||||
}
|
||||
|
||||
test('Python and Java retries preserve UUID and language/content changes create a new intent', async () => {
|
||||
const storage = memory()
|
||||
const keys: string[] = []
|
||||
for (const language of ['python313', 'java21'] as const) {
|
||||
const managed = { ...input, language }
|
||||
await assert.rejects(
|
||||
submissionIntent(storage, 'owner').submit(managed, async (key) => {
|
||||
keys.push(key)
|
||||
throw new Error('uncertain delivery')
|
||||
}),
|
||||
)
|
||||
const failedKey = keys.at(-1)
|
||||
await submissionIntent(storage, 'owner').submit(managed, async (key) => {
|
||||
assert.equal(key, failedKey)
|
||||
return 'saved-' + language
|
||||
})
|
||||
}
|
||||
assert.notEqual(keys[0], keys[1])
|
||||
await submissionIntent(storage, 'owner').submit(
|
||||
{ ...input, language: 'java21', source: 'changed Java' },
|
||||
async (key) => {
|
||||
assert.notEqual(key, keys[1])
|
||||
return 'changed-id'
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('timeout and reload reuse persisted key; double click has one flight; content and owner change key', async () => {
|
||||
const storage = memory()
|
||||
const keys: string[] = []
|
||||
const intent = submissionIntent(storage, 'owner-a')
|
||||
let respond: (id: string) => void = () => {}
|
||||
let sent: () => void = () => {}
|
||||
const sending = new Promise<void>((resolve) => {
|
||||
sent = resolve
|
||||
})
|
||||
const send = async (key: string) => {
|
||||
keys.push(key)
|
||||
sent()
|
||||
return new Promise<string>((resolve) => {
|
||||
respond = resolve
|
||||
})
|
||||
@@ -36,7 +68,7 @@ test('timeout and reload reuse persisted key; double click has one flight; conte
|
||||
const a = intent.submit(input, send)
|
||||
const b = intent.submit(input, send)
|
||||
assert.equal(a, b)
|
||||
await flush()
|
||||
await sending
|
||||
assert.equal(keys.length, 1)
|
||||
respond('real-id')
|
||||
assert.equal(await a, 'real-id')
|
||||
|
||||
@@ -142,6 +142,7 @@ test('pagehide preserves the selected language and keeps problem drafts separate
|
||||
c: codeTemplates.c,
|
||||
cpp: '// C++ draft',
|
||||
python: '# Python draft',
|
||||
java: codeTemplates.java,
|
||||
rust: codeTemplates.rust,
|
||||
},
|
||||
})
|
||||
@@ -190,3 +191,44 @@ test('old Python/Rust drafts survive adding C17; C and C++ retain separate conte
|
||||
assert.equal(env.read()?.drafts.python, '# original Python')
|
||||
assert.equal(env.read()?.drafts.rust, '// original Rust')
|
||||
})
|
||||
|
||||
test('old drafts acquire Java without replacing their contents; four languages survive reload and version changes', (t) => {
|
||||
const env = browser(t)
|
||||
env.storage.items.set(
|
||||
'kf-oj:code-draft:version-a',
|
||||
JSON.stringify({
|
||||
version: 1,
|
||||
language: 'python',
|
||||
drafts: { python: '# old Python', cpp: '// old C++', rust: '// old Rust' },
|
||||
}),
|
||||
)
|
||||
const draft = env.open('version-a')
|
||||
assert.equal(draft.code.value, '# old Python')
|
||||
draft.language.value = 'java'
|
||||
assert.equal(draft.code.value, codeTemplates.java)
|
||||
draft.code.value = '// Java draft'
|
||||
draft.language.value = 'c'
|
||||
draft.code.value = '// C draft'
|
||||
draft.language.value = 'java'
|
||||
env.page.dispatchEvent(new Event('pagehide'))
|
||||
draft.scope.stop()
|
||||
const restored = env.open('version-a')
|
||||
assert.equal(restored.language.value, 'java')
|
||||
assert.equal(restored.code.value, '// Java draft')
|
||||
for (const [language, contents] of [
|
||||
['c', '// C draft'],
|
||||
['cpp', '// old C++'],
|
||||
['python', '# old Python'],
|
||||
['rust', '// old Rust'],
|
||||
] as const) {
|
||||
restored.language.value = language
|
||||
assert.equal(restored.code.value, contents)
|
||||
}
|
||||
const other = env.open('version-b')
|
||||
other.language.value = 'java'
|
||||
assert.equal(other.code.value, codeTemplates.java)
|
||||
other.code.value = '// other version Java'
|
||||
other.save()
|
||||
assert.equal(env.read('version-a')?.drafts.java, '// Java draft')
|
||||
assert.equal(env.read('version-b')?.drafts.java, '// other version Java')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user