Repository: eslint/eslint
File: lib/rule-tester/rule-tester.js (JavaScript)

Code before:
		"detected duplicate test case",
	);
	seenTestCases.add(serializedTestCase);
}

/**
 * Asserts that a rule is valid.
 * A valid rule must be an object with a `create` method.
 * @param {Object} rule The rule to check.
 * @param {string} ruleName The name of the rule.
 * @returns {void}
 * @throws {AssertionError} If the rule is not valid.
 */
function assertRule(rule, ruleName) {
	assert.ok(
		rule && typeof rule === "object" && typeof rule.create === "function",
		`Rule ${ruleName} must be an object with a \`create\` method`,
	);
}

/**
 * Asserts that a test scenario object is valid.
 * A valid test scenario object must have `valid` and `invalid` properties, both of
 * which must be arrays.
 * @param {Object} test The test scenario object to check.
 * @param {string} ruleName The name of the rule being tested.
 * @returns {void}
 * @throws {AssertionError} If the test scenario object is not valid.
 */
function assertTest(test, ruleName) {
	assertObject(
		test,
		`Test Scenarios for rule ${ruleName} : Could not find test scenario object`,
	);

	const hasValid = Array.isArray(test.valid);
	const hasInvalid = Array.isArray(test.invalid);

	assert.ok(
		hasValid && hasInvalid,
		`Test Scenarios for rule ${ruleName} : No valid or invalid test scenarios found`,
	);
}

/**
 * Asserts that a valid test case object is valid.
 * A valid test case must specify a string value for 'code' and must not have 'errors' or 'output' properties.
 * Optional properties are checked for correct types.
 * @param {Object} item The valid test case object to check.
 * @param {Set<string>} seenTestCases Set of serialized test cases to check for duplicates.
 * @returns {void}

Review comment (refactor):
This could be refactored in two functions: assertions only for valid test cases (e.g. `errors` cannot be set) and tests shared with invalid test cases (e.g. `code` must be a string, ...) rather than duplicate the checks for the invalid case.

Code after:
		);
	}
	if (hasOwnProperty(item, "filename")) {
		assert.ok(
			typeof item.filename === "string",
			"Optional test case property 'filename' must be a string",
		);
	}
	if (hasOwnProperty(item, "options")) {
		assert.ok(
			Array.isArray(item.options),
			"Optional test case property 'options' must be an array",
		);
	}
}

/**
 * Asserts that a valid test case object is valid.
 * A valid test case must specify a string value for 'code'.
 * Optional properties are checked for correct types.
 * @param {Object} item The valid test case object to check.
 * @param {Set<string>} seenTestCases Set of serialized test cases to check for duplicates.
 * @returns {void}
 * @throws {AssertionError} If the test case is not valid.
 */
function assertValidTestCase(item, seenTestCases) {
	// must not have properties of invalid test cases
	assert.ok(
		item.errors === void 0,
		"Valid test case must not have 'errors' property",
	);
	assert.ok(
		item.output === void 0,
		"Valid test case must not have 'output' property",
	);

	assertTestCommonProperties(item);
	checkDuplicateTestCase(item, seenTestCases);
}

/**
 * Asserts that the invalid test case object is valid.
 * An invalid test case must specify a string value for 'code' and must have 'errors' property.
 * Optional properties are checked for correct types.
 * @param {Object} item The invalid test case object to check.
 * @param {Set<string>} seenTestCases Set of serialized test cases to check for duplicates.
 * @param {string} ruleName The name of the rule being tested.
 * @returns {void}
 * @throws {AssertionError} If the test case is not valid.
 */
function assertInvalidTestCase(item, seenTestCases, ruleName) {