| { |
| "tasks": [ |
| { |
| "id": "train_cache_mutation_shared_list", |
| "split": "train", |
| "title": "Cache mutation due to shared list reference", |
| "instruction": "The cache stores references to lists, causing data to be unintentionally mutated when the original list changes. The cache should store a defensive copy of the list.", |
| "files": { |
| "cache.py": "class Cache:\n def __init__(self):\n self._cache = {}\n def set(self, key, value):\n self._cache[key] = value\n def get(self, key):\n return self._cache.get(key)", |
| "tests/test_cache.py": "from cache import Cache\n\ndef test_cache_defensive_copy():\n c = Cache()\n data = [1, 2]\n c.set('a', data)\n data.append(3)\n cached = c.get('a')\n assert cached == [1, 2], f\"Expected [1, 2], got {cached}\"" |
| }, |
| "checks": [ |
| { |
| "type": "contains", |
| "path": "cache.py", |
| "text": "list(value)" |
| }, |
| { |
| "type": "not_contains", |
| "path": "cache.py", |
| "text": "self._cache[key] = value" |
| }, |
| { |
| "type": "regex", |
| "path": "cache.py", |
| "pattern": "self\\._cache\\[key\\] = .*copy" |
| } |
| ], |
| "failure_messages": [ |
| "Cache does not make a defensive copy of the list.", |
| "Cache still stores a direct reference to the list.", |
| "Cache assignment should use a copy of the value." |
| ], |
| "canonical_solution": "Wrap value with list() or use .copy() when storing in cache to avoid mutation." |
| }, |
| { |
| "id": "train_py_timeout_zero_bug", |
| "split": "train", |
| "title": "Timeout helper treats zero as infinite", |
| "instruction": "A timeout helper function treats timeout=0 as no timeout instead of immediate timeout. The function should treat zero as an immediate timeout.", |
| "files": { |
| "timeout_helper.py": "def has_timed_out(start, timeout, now):\n if timeout is None:\n return False\n if timeout <= 0:\n return False # BUG: should be True\n return (now - start) > timeout", |
| "tests/test_timeout.py": "from timeout_helper import has_timed_out\n\ndef test_timeout_zero():\n assert has_timed_out(10, 0, 10) == True\n assert has_timed_out(10, None, 12) == False" |
| }, |
| "checks": [ |
| { |
| "type": "contains", |
| "path": "timeout_helper.py", |
| "text": "return True" |
| }, |
| { |
| "type": "not_contains", |
| "path": "timeout_helper.py", |
| "text": "return False # BUG: should be True" |
| }, |
| { |
| "type": "regex", |
| "path": "timeout_helper.py", |
| "pattern": "if timeout <= 0:.*return True" |
| } |
| ], |
| "failure_messages": [ |
| "Timeout of 0 does not cause immediate timeout.", |
| "Zero timeout still returns False.", |
| "Timeout helper does not return True for timeout <= 0." |
| ], |
| "canonical_solution": "Return True for timeout <= 0 to indicate an immediate timeout." |
| }, |
| { |
| "id": "train_py_retry_backoff_not_applied", |
| "split": "train", |
| "title": "Retry helper ignores backoff delay", |
| "instruction": "A retry helper is supposed to apply a backoff delay between attempts but currently does not. It should call the provided backoff function after each failed attempt except the last.", |
| "files": { |
| "retry.py": "def retry(retries, func, backoff):\n for i in range(retries):\n try:\n return func()\n except Exception:\n continue # Should apply backoff here\n raise RuntimeError('All retries failed')", |
| "tests/test_retry.py": "from retry import retry\n\ndef test_retry_applies_backoff():\n calls = []\n def func():\n calls.append('try')\n raise ValueError()\n backoffs = []\n def backoff():\n backoffs.append('b')\n try:\n retry(3, func, backoff)\n except RuntimeError:\n pass\n assert backoffs == ['b', 'b'], f\"Expected 2 backoff calls, got {len(backoffs)}\"" |
| }, |
| "checks": [ |
| { |
| "type": "contains", |
| "path": "retry.py", |
| "text": "backoff()" |
| }, |
| { |
| "type": "regex", |
| "path": "retry.py", |
| "pattern": "except Exception:\\s*backoff\\(\\)" |
| }, |
| { |
| "type": "not_contains", |
| "path": "retry.py", |
| "text": "continue # Should apply backoff here" |
| } |
| ], |
| "failure_messages": [ |
| "Backoff is not called after failed retry attempts.", |
| "Missing call to backoff() after exceptions.", |
| "Backoff is not applied between retries." |
| ], |
| "canonical_solution": "Call backoff() in the except block before continuing to next retry." |
| }, |
| { |
| "id": "train_py_registry_filter_incorrect", |
| "split": "train", |
| "title": "Registry filter fails to exclude items", |
| "instruction": "A registry filtering method does not properly exclude items by type. The filter should only return registered items matching the given type.", |
| "files": { |
| "registry.py": "class Registry:\n def __init__(self):\n self.items = []\n def register(self, item):\n self.items.append(item)\n def filter_by_type(self, typ):\n return self.items # BUG: should filter by typ", |
| "tests/test_registry.py": "from registry import Registry\n\ndef test_filter_by_type():\n class A: pass\n class B: pass\n r = Registry()\n a = A(); b = B()\n r.register(a)\n r.register(b)\n result = r.filter_by_type(A)\n assert result == [a], f\"Expected only A instance, got {result}\"" |
| }, |
| "checks": [ |
| { |
| "type": "contains", |
| "path": "registry.py", |
| "text": "isinstance(item, typ)" |
| }, |
| { |
| "type": "not_contains", |
| "path": "registry.py", |
| "text": "return self.items # BUG: should filter by typ" |
| }, |
| { |
| "type": "regex", |
| "path": "registry.py", |
| "pattern": "return \\[item for item in self\\.items if isinstance\\(item, typ\\)\\]" |
| } |
| ], |
| "failure_messages": [ |
| "filter_by_type does not filter by type.", |
| "Returned all items instead of just matching type.", |
| "Registry does not exclude items of the wrong type." |
| ], |
| "canonical_solution": "Return a filtered list with isinstance(item, typ) in filter_by_type." |
| }, |
| { |
| "id": "train_test_discovery_missing_test", |
| "split": "train", |
| "title": "Test discovery skips non-prefixed test files", |
| "instruction": "The test discovery script only finds files with a 'test_' prefix but should also include files with a '_test.py' suffix.", |
| "files": { |
| "discover.py": "import os\n\ndef discover_tests():\n return [f for f in os.listdir('tests') if f.startswith('test_') and f.endswith('.py')]", |
| "tests/test_discovery.py": "# test_discovery.py\nfrom discover import discover_tests\n\ndef test_discovers_suffix_files(tmp_path, monkeypatch):\n d = tmp_path / 'tests'\n d.mkdir()\n (d / 'test_a.py').write_text('pass')\n (d / 'b_test.py').write_text('pass')\n monkeypatch.setattr('os.listdir', lambda _: ['test_a.py', 'b_test.py'])\n out = discover_tests()\n assert 'b_test.py' in out, f\"Discovery failed to find b_test.py: {out}\"" |
| }, |
| "checks": [ |
| { |
| "type": "contains", |
| "path": "discover.py", |
| "text": "or f.endswith('_test.py')" |
| }, |
| { |
| "type": "regex", |
| "path": "discover.py", |
| "pattern": "f\\.startswith\\('test_'\\)|f\\.endswith\\('_test\\.py'\\)" |
| } |
| ], |
| "failure_messages": [ |
| "Discovery does not find files with '_test.py' suffix.", |
| "Test files not starting with prefix are skipped." |
| ], |
| "canonical_solution": "Include both files with 'test_' prefix and '_test.py' suffix in discovery." |
| }, |
| { |
| "id": "train_plugin_ordering_bug", |
| "split": "train", |
| "title": "Plugin ordering not preserved", |
| "instruction": "The plugin registry should preserve the order in which plugins are registered, but it currently sorts them alphabetically. It should keep insertion order.", |
| "files": { |
| "plugin.py": "class PluginRegistry:\n def __init__(self):\n self.plugins = []\n def register(self, plugin):\n self.plugins.append(plugin)\n def get_plugins(self):\n return sorted(self.plugins, key=lambda x: x.__name__)", |
| "tests/test_plugin.py": "from plugin import PluginRegistry\n\ndef test_plugin_ordering():\n class A: pass\n class B: pass\n reg = PluginRegistry()\n reg.register(A)\n reg.register(B)\n order = reg.get_plugins()\n assert order == [A, B], f\"Expected [A, B], got {order}\"" |
| }, |
| "checks": [ |
| { |
| "type": "not_contains", |
| "path": "plugin.py", |
| "text": "sorted(self.plugins" |
| }, |
| { |
| "type": "contains", |
| "path": "plugin.py", |
| "text": "return self.plugins" |
| } |
| ], |
| "failure_messages": [ |
| "Plugins are not returned in registration order.", |
| "get_plugins still sorts plugins alphabetically." |
| ], |
| "canonical_solution": "Remove the sorted call; just return self.plugins to preserve registration order." |
| }, |
| { |
| "id": "eval_js_trim_slash_array_bug", |
| "split": "eval", |
| "title": "JS utility does not trim slashes from all array entries", |
| "instruction": "A JavaScript utility is supposed to trim leading and trailing slashes from every string in an array, but it only works on the first element. All elements should be trimmed.", |
| "files": { |
| "utils/trimSlashes.js": "function trimSlashes(arr) {\n arr[0] = arr[0].replace(/^\\/+|\\/+$/g, '');\n return arr;\n}\nmodule.exports = trimSlashes;", |
| "tests/test_trimSlashes.js": "const trimSlashes = require('../utils/trimSlashes');\n\ntest('trims slashes in all entries', () => {\n expect(trimSlashes(['/foo/', '/bar/', '/baz/'])).toEqual(['foo', 'bar', 'baz']);\n});" |
| }, |
| "checks": [ |
| { |
| "type": "contains", |
| "path": "utils/trimSlashes.js", |
| "text": "map(" |
| }, |
| { |
| "type": "regex", |
| "path": "utils/trimSlashes.js", |
| "pattern": "\\.map\\(.*replace\\(" |
| }, |
| { |
| "type": "not_contains", |
| "path": "utils/trimSlashes.js", |
| "text": "arr[0] =" |
| } |
| ], |
| "failure_messages": [ |
| "Only the first array element is trimmed.", |
| "Should use map to trim all array entries.", |
| "Direct assignment to arr[0] is still present." |
| ], |
| "canonical_solution": "Use arr.map to apply the replace to all entries in the array." |
| }, |
| { |
| "id": "eval_js_package_script_order_bug", |
| "split": "eval", |
| "title": "JS package scripts run in incorrect order", |
| "instruction": "The package scripts runner executes scripts in object key order, not in the order defined in the scripts array. It should maintain the declared order.", |
| "files": { |
| "scripts/runScripts.js": "function runScripts(scripts, actions) {\n const keys = Object.keys(scripts);\n keys.forEach(k => actions.push(k));\n}\nmodule.exports = runScripts;", |
| "tests/test_runScripts.js": "const runScripts = require('../scripts/runScripts');\n\ntest('runs in order', () => {\n const scripts = {build: '', test: '', lint: ''};\n const order = [];\n runScripts(['lint', 'build', 'test'], order);\n expect(order).toEqual(['lint', 'build', 'test']);\n});" |
| }, |
| "checks": [ |
| { |
| "type": "not_contains", |
| "path": "scripts/runScripts.js", |
| "text": "Object.keys" |
| }, |
| { |
| "type": "contains", |
| "path": "scripts/runScripts.js", |
| "text": "forEach(" |
| } |
| ], |
| "failure_messages": [ |
| "Uses object key order instead of provided array order.", |
| "Should iterate over scripts array, not Object.keys." |
| ], |
| "canonical_solution": "Iterate over the provided scripts array and push keys in order." |
| } |
| ] |
| } |