quarc/tests/unit/test-nested-for-loops.ts

429 lines
11 KiB
JavaScript

#!/usr/bin/env node
// Polyfill window dla Node.js
(global as any).window = (global as any).window || { __quarc: {} };
(global as any).window.__quarc = (global as any).window.__quarc || {};
import { signal, computed, effect } from '../../core/angular/signals';
interface TestResult {
name: string;
passed: boolean;
error?: string;
}
const results: TestResult[] = [];
function test(name: string, fn: () => void | Promise<void>): void {
try {
const result = fn();
if (result instanceof Promise) {
result
.then(() => results.push({ name, passed: true }))
.catch((e) => results.push({ name, passed: false, error: String(e) }));
} else {
results.push({ name, passed: true });
}
} catch (e) {
results.push({ name, passed: false, error: String(e) });
}
}
function assertEqual<T>(actual: T, expected: T, message?: string): void {
if (actual !== expected) {
throw new Error(
`${message || 'Assertion failed'}\nExpected: ${expected}\nActual: ${actual}`,
);
}
}
function assertDeepEqual<T>(actual: T, expected: T, message?: string): void {
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
throw new Error(
`${message || 'Assertion failed'}\nExpected: ${JSON.stringify(expected)}\nActual: ${JSON.stringify(actual)}`,
);
}
}
console.log('\n=== TESTY ZAGNIEŻDŻONYCH PĘTLI FOR ===\n');
interface LayoutLine {
id: number;
items: { id: number; name: string }[];
}
interface Layout {
lines: LayoutLine[];
width: number;
height: number;
}
test('nested-for: iteracja po tablicy linii i elementów wewnątrz', () => {
const layout = signal<Layout>({
lines: [
{ id: 1, items: [{ id: 101, name: 'item1' }, { id: 102, name: 'item2' }] },
{ id: 2, items: [{ id: 201, name: 'item3' }] },
],
width: 100,
height: 100,
});
const renderedItems: string[] = [];
effect(() => {
renderedItems.length = 0;
for (const line of layout().lines) {
for (const item of line.items) {
renderedItems.push(`line${line.id}-${item.name}`);
}
}
});
assertDeepEqual(renderedItems, ['line1-item1', 'line1-item2', 'line2-item3']);
});
test('nested-for: aktualizacja po zmianie zewnętrznej tablicy', () => {
const layout = signal<Layout>({
lines: [
{ id: 1, items: [{ id: 101, name: 'a' }] },
],
width: 100,
height: 100,
});
const renderedItems: string[] = [];
effect(() => {
renderedItems.length = 0;
for (const line of layout().lines) {
for (const item of line.items) {
renderedItems.push(item.name);
}
}
});
assertEqual(renderedItems.length, 1);
layout.set({
lines: [
{ id: 1, items: [{ id: 101, name: 'a' }] },
{ id: 2, items: [{ id: 201, name: 'b' }, { id: 202, name: 'c' }] },
],
width: 100,
height: 100,
});
assertEqual(renderedItems.length, 3);
assertDeepEqual(renderedItems, ['a', 'b', 'c']);
});
test('nested-for: aktualizacja po zmianie wewnętrznej tablicy', () => {
const layout = signal<Layout>({
lines: [
{ id: 1, items: [{ id: 101, name: 'x' }] },
],
width: 100,
height: 100,
});
const renderedItems: string[] = [];
effect(() => {
renderedItems.length = 0;
for (const line of layout().lines) {
for (const item of line.items) {
renderedItems.push(item.name);
}
}
});
assertEqual(renderedItems.length, 1);
layout.set({
lines: [
{ id: 1, items: [{ id: 101, name: 'x' }, { id: 102, name: 'y' }, { id: 103, name: 'z' }] },
],
width: 100,
height: 100,
});
assertEqual(renderedItems.length, 3);
assertDeepEqual(renderedItems, ['x', 'y', 'z']);
});
test('nested-for: computed zliczający elementy w zagnieżdżonych tablicach', () => {
const layout = signal<Layout>({
lines: [
{ id: 1, items: [{ id: 101, name: 'a' }, { id: 102, name: 'b' }] },
{ id: 2, items: [{ id: 201, name: 'c' }] },
],
width: 100,
height: 100,
});
const totalItems = computed(() => {
let count = 0;
for (const line of layout().lines) {
count += line.items.length;
}
return count;
});
assertEqual(totalItems(), 3);
layout.set({
lines: [
{ id: 1, items: [{ id: 101, name: 'a' }] },
],
width: 100,
height: 100,
});
assertEqual(totalItems(), 1);
});
test('nested-for: symulacja renderowania DOM z zagnieżdżonymi pętlami', () => {
const layout = signal<Layout>({
lines: [],
width: 0,
height: 0,
});
const domStructure: { lineId: number; itemIds: number[] }[] = [];
effect(() => {
domStructure.length = 0;
for (const line of layout().lines) {
const lineEntry = { lineId: line.id, itemIds: [] as number[] };
for (const item of line.items) {
lineEntry.itemIds.push(item.id);
}
domStructure.push(lineEntry);
}
});
assertEqual(domStructure.length, 0);
layout.set({
lines: [
{ id: 1, items: [{ id: 10, name: 'a' }, { id: 11, name: 'b' }] },
{ id: 2, items: [{ id: 20, name: 'c' }] },
{ id: 3, items: [] },
],
width: 800,
height: 600,
});
assertEqual(domStructure.length, 3);
assertDeepEqual(domStructure[0], { lineId: 1, itemIds: [10, 11] });
assertDeepEqual(domStructure[1], { lineId: 2, itemIds: [20] });
assertDeepEqual(domStructure[2], { lineId: 3, itemIds: [] });
});
test('nested-for: wielokrotne aktualizacje zagnieżdżonych danych', () => {
const layout = signal<Layout>({
lines: [{ id: 1, items: [{ id: 1, name: 'initial' }] }],
width: 100,
height: 100,
});
let renderCount = 0;
const lastRendered: string[] = [];
effect(() => {
renderCount++;
lastRendered.length = 0;
for (const line of layout().lines) {
for (const item of line.items) {
lastRendered.push(item.name);
}
}
});
assertEqual(renderCount, 1);
assertDeepEqual(lastRendered, ['initial']);
layout.set({
lines: [{ id: 1, items: [{ id: 1, name: 'update1' }] }],
width: 100,
height: 100,
});
assertEqual(renderCount, 2);
assertDeepEqual(lastRendered, ['update1']);
layout.set({
lines: [
{ id: 1, items: [{ id: 1, name: 'a' }, { id: 2, name: 'b' }] },
{ id: 2, items: [{ id: 3, name: 'c' }] },
],
width: 200,
height: 200,
});
assertEqual(renderCount, 3);
assertDeepEqual(lastRendered, ['a', 'b', 'c']);
});
test('nested-for: trzy poziomy zagnieżdżenia', () => {
interface DeepLayout {
sections: {
id: number;
rows: {
id: number;
cells: { id: number; value: string }[];
}[];
}[];
}
const deepLayout = signal<DeepLayout>({
sections: [
{
id: 1,
rows: [
{ id: 11, cells: [{ id: 111, value: 'A' }, { id: 112, value: 'B' }] },
{ id: 12, cells: [{ id: 121, value: 'C' }] },
],
},
{
id: 2,
rows: [
{ id: 21, cells: [{ id: 211, value: 'D' }] },
],
},
],
});
const allValues: string[] = [];
effect(() => {
allValues.length = 0;
for (const section of deepLayout().sections) {
for (const row of section.rows) {
for (const cell of row.cells) {
allValues.push(cell.value);
}
}
}
});
assertDeepEqual(allValues, ['A', 'B', 'C', 'D']);
deepLayout.set({
sections: [
{
id: 1,
rows: [
{ id: 11, cells: [{ id: 111, value: 'X' }, { id: 112, value: 'Y' }, { id: 113, value: 'Z' }] },
],
},
],
});
assertDeepEqual(allValues, ['X', 'Y', 'Z']);
});
test('nested-for: pusta tablica zewnętrzna', () => {
const layout = signal<Layout>({
lines: [],
width: 0,
height: 0,
});
const renderedItems: string[] = [];
effect(() => {
renderedItems.length = 0;
for (const line of layout().lines) {
for (const item of line.items) {
renderedItems.push(item.name);
}
}
});
assertEqual(renderedItems.length, 0);
layout.set({
lines: [{ id: 1, items: [{ id: 1, name: 'first' }] }],
width: 100,
height: 100,
});
assertEqual(renderedItems.length, 1);
assertEqual(renderedItems[0], 'first');
});
test('nested-for: puste tablice wewnętrzne', () => {
const layout = signal<Layout>({
lines: [
{ id: 1, items: [] },
{ id: 2, items: [] },
],
width: 100,
height: 100,
});
let lineCount = 0;
let itemCount = 0;
effect(() => {
lineCount = 0;
itemCount = 0;
for (const line of layout().lines) {
lineCount++;
for (const item of line.items) {
itemCount++;
}
}
});
assertEqual(lineCount, 2);
assertEqual(itemCount, 0);
layout.set({
lines: [
{ id: 1, items: [{ id: 1, name: 'a' }] },
{ id: 2, items: [] },
{ id: 3, items: [{ id: 2, name: 'b' }, { id: 3, name: 'c' }] },
],
width: 100,
height: 100,
});
assertEqual(lineCount, 3);
assertEqual(itemCount, 3);
});
async function runTests() {
await new Promise(resolve => setTimeout(resolve, 100));
console.log('\n=== PODSUMOWANIE ===');
let passed = 0;
let failed = 0;
for (const result of results) {
if (result.passed) {
console.log(`${result.name}`);
passed++;
} else {
console.log(`${result.name}`);
console.log(` Error: ${result.error}`);
failed++;
}
}
console.log(`\n✅ Testy zaliczone: ${passed}`);
console.log(`❌ Testy niezaliczone: ${failed}`);
console.log(`📊 Procent sukcesu: ${((passed / results.length) * 100).toFixed(1)}%`);
if (failed === 0) {
console.log('\n🎉 Wszystkie testy przeszły pomyślnie!\n');
} else {
console.log('\n❌ Niektóre testy nie przeszły.\n');
process.exit(1);
}
}
runTests();