@@ -7,42 +7,61 @@ import { AssertionError } from "./assertion_error.ts";
77/** An array-like object (`Array`, `Uint8Array`, `NodeList`, etc.) that is not a string */
88export type ArrayLikeArg < T > = ArrayLike < T > & object ;
99
10+ function isPrimitive ( value : unknown ) : boolean {
11+ return value === null ||
12+ typeof value !== "object" && typeof value !== "function" ;
13+ }
14+
1015/**
11- * Make an assertion that `actual` includes the `expected` values. If not then
12- * an error will be thrown.
16+ * Asserts that `actual` contains all values in `expected`, using deep equality
17+ * for non-primitive values.
18+ *
19+ * @example Usage with primitives
20+ * ```ts ignore
21+ * import { assertArrayIncludes } from "@std/assert";
1322 *
14- * Type parameter can be specified to ensure values under comparison have the
15- * same type.
23+ * assertArrayIncludes([1, 2, 3], [2, 3]); // Passes
24+ * assertArrayIncludes([1, 2, 3], [4]); // Throws
25+ * ```
1626 *
17- * @example Usage
27+ * @example Usage with objects (deep equality)
1828 * ```ts ignore
1929 * import { assertArrayIncludes } from "@std/assert";
2030 *
21- * assertArrayIncludes([1, 2], [2]); // Doesn't throw
22- * assertArrayIncludes([1, 2], [3]); // Throws
31+ * assertArrayIncludes([{ a: 1 }, { b: 2 }], [{ a: 1 }]); // Passes
2332 * ```
2433 *
25- * @typeParam T The type of the elements in the array to compare.
26- * @param actual The array-like object to check for.
27- * @param expected The array-like object to check for.
28- * @param msg The optional message to display if the assertion fails.
34+ * @typeParam T The element type of the arrays.
35+ * @param actual The array-like object to search within.
36+ * @param expected The values that must be present in `actual`.
37+ * @param msg Optional message to display on failure.
38+ * @throws {AssertionError } If any value in `expected` is not found in `actual`.
2939 */
3040export function assertArrayIncludes < T > (
3141 actual : ArrayLikeArg < T > ,
3242 expected : ArrayLikeArg < T > ,
3343 msg ?: string ,
34- ) {
44+ ) : void {
3545 const missing : unknown [ ] = [ ] ;
36- for ( let i = 0 ; i < expected . length ; i ++ ) {
37- let found = false ;
38- for ( let j = 0 ; j < actual . length ; j ++ ) {
39- if ( equal ( expected [ i ] , actual [ j ] ) ) {
40- found = true ;
41- break ;
46+ const expectedLen = expected . length ;
47+ const actualLen = actual . length ;
48+ for ( let i = 0 ; i < expectedLen ; i ++ ) {
49+ const item = expected [ i ] ;
50+ let found : boolean ;
51+ if ( isPrimitive ( item ) ) {
52+ // Fast path
53+ found = Array . prototype . includes . call ( actual , item ) ;
54+ } else {
55+ found = false ;
56+ for ( let j = 0 ; j < actualLen ; j ++ ) {
57+ if ( equal ( item , actual [ j ] ) ) {
58+ found = true ;
59+ break ;
60+ }
4261 }
4362 }
4463 if ( ! found ) {
45- missing . push ( expected [ i ] ) ;
64+ missing . push ( item ) ;
4665 }
4766 }
4867 if ( missing . length === 0 ) {
0 commit comments