it('should detect conflicting events', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.validTimeSlot, { minLength: 2, maxLength: 5 }),
          (events) => {
            // Property: Conflict detection should be reliable
            const hasConflict = (
              event1: (typeof events)[0],
              event2: (typeof events)[0],
            ): boolean => {
              return (
                (event1.start < event2.end && event1.end > event2.start) ||
                (event2.start < event1.end && event2.end > event1.start)
              );
            };

            // Check all pairs for conflicts
            let conflictCount = 0;
            for (let i = 0; i < events.length; i++) {
              for (let j = i + 1; j < events.length; j++) {
                if (hasConflict(events[i], events[j])) {
                  conflictCount++;
                }
              }
            }

            // Property: Conflict detection should be deterministic
            return conflictCount >= 0; // Should always return a non-negative count
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The test ensures that the conflict detection between event time slots is reliable and always produces a non-negative count of conflicts when checking all pairs.


unknown

it('should handle daylight saving transitions', () => {
      fc.assert(
        fc.property(
          fc.date({ min: new Date('2024-03-01'), max: new Date('2024-04-01') }), // Around DST transition
          (date) => {
            // Property: Time calculations should account for DST changes
            const oneDayLater = new Date(date.getTime() + 24 * 60 * 60 * 1000);
            const timeDifference = oneDayLater.getTime() - date.getTime();

            // Should be either 23, 24, or 25 hours depending on DST transition
            const hoursDifference = timeDifference / (60 * 60 * 1000);

            return hoursDifference >= 23 && hoursDifference <= 25;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Time calculations should correctly account for daylight saving time changes, resulting in a 23, 24, or 25-hour difference.


it('should maintain UTC consistency', () => {
      fc.assert(
        fc.property(fc.date(), (date) => {
          // Property: UTC conversion should be reversible
          const utcTime = date.getTime();
          const reconstructed = new Date(utcTime);

          return reconstructed.getTime() === date.getTime();
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: UTC conversion of a date should be reversible, ensuring the reconstructed date has the same timestamp as the original.


it('should maintain data through ISO string conversion', () => {
      fc.assert(
        fc.property(fc.date(), (date) => {
          // Property: ISO string conversion should preserve date information
          const isoString = date.toISOString();
          const parsed = new Date(isoString);

          return parsed.getTime() === date.getTime();
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Converting a date to an ISO string and back should result in an equivalent date object with the same time value.


it('should count school days correctly', () => {
      fc.assert(
        fc.property(
          fc.tuple(domainArbitraries.schoolDay, domainArbitraries.schoolDay),
          ([startDate, endDate]) => {
            if (startDate > endDate) {
              [startDate, endDate] = [endDate, startDate];
            }

            const schoolDays = calculateSchoolDaysInRange(startDate, endDate);

            // Property: School days should be non-negative and reasonable
            const totalDays =
              Math.ceil((endDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1000)) + 1;

            return schoolDays >= 0 && schoolDays <= totalDays;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The function `calculateSchoolDaysInRange` must return a non-negative count of school days that does not exceed the total chronological days between two adjusted dates.


it("should parse CSV string", () =>
    fc.assert(
      fc.asyncProperty(
        fc.gen().map((g) => {
          const header = g(FC.header);
          const EOL = g(FC.eol);
          const EOF = g(fc.boolean);
          const csvData = [
            ...g(FC.csvData, {
              rowsConstraints: {
                minLength: 1,
              },
              columnsConstraints: {
                minLength: header.length,
                maxLength: header.length,
              },
            }),
            // Last row is not empty for testing.
            g(FC.row, {
              fieldConstraints: {
                minLength: 1,
              },
              columnsConstraints: {
                minLength: header.length,
                maxLength: header.length,
              },
            }),
          ];
          const csv = [
            header.map((v) => escapeField(v)).join(","),
            EOL,
            ...csvData.flatMap((row, i) => [
              ...row.map((v) => escapeField(v)).join(","),
              ...(EOF || csvData.length - 1 !== i ? [EOL] : []),
            ]),
          ].join("");
          const data = csvData.map((row) =>
            Object.fromEntries(row.map((v, i) => [header[i], v])),
          );
          return { data, csv };
        }),
        async ({ data, csv }) => {
          let i = 0;
          for await (const row of parse(csv)) {
            expect(row).toEqual(data[i++]);
          }
        },
      ),
      {
        examples: [
          [{ csv: "a,b,c\n1,2,3", data: [{ a: "1", b: "2", c: "3" }] }],
          [{ csv: "a,b,c\n1,,3", data: [{ a: "1", b: "", c: "3" }] }],
          [{ csv: "a,b,c\n1,2,3\n", data: [{ a: "1", b: "2", c: "3" }] }],
          [
            {
              csv: "a,b,c\n\n1,2,3",
              data: [
                { a: "", b: "", c: "" },
                { a: "1", b: "2", c: "3" },
              ],
            },
          ],
        ],
      },
    ))

Summary: The `parse` function should correctly convert a generated CSV string into an array of objects, ensuring that each row corresponds to the header fields and matches the expected data structure.


it('should find next school day correctly', () => {
      fc.assert(
        fc.property(
          fc.date({ min: new Date('2024-01-01'), max: new Date('2024-12-31') }),
          (date) => {
            const nextSchoolDay = getNextSchoolDay(date);

            // Property: Next school day should be after current date and on a weekday
            const isAfter = nextSchoolDay > date;
            const isWeekday = nextSchoolDay.getDay() >= 1 && nextSchoolDay.getDay() <= 5;

            return isAfter && isWeekday;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The test verifies that `getNextSchoolDay` returns a date that is both after the given date and falls on a weekday.


it("should parse Uint8Arrayed CSV", () =>
    fc.assert(
      fc.asyncProperty(
        fc.gen().map((g) => {
          const header = g(FC.header, {
            fieldConstraints: {
              kindExcludes: ["string16bits"],
            },
          });
          const EOL = g(FC.eol);
          const EOF = g(fc.boolean);
          const csvData = [
            ...g(FC.csvData, {
              rowsConstraints: {
                minLength: 1,
              },
              columnsConstraints: {
                minLength: header.length,
                maxLength: header.length,
              },
              fieldConstraints: {
                kindExcludes: ["string16bits"],
              },
            }),
            // Last row is not empty for testing.
            g(FC.row, {
              fieldConstraints: {
                minLength: 1,
                kindExcludes: ["string16bits"],
              },
              columnsConstraints: {
                minLength: header.length,
                maxLength: header.length,
              },
            }),
          ];
          const csv = [
            header.map((v) => escapeField(v)).join(","),
            EOL,
            ...csvData.flatMap((row, i) => [
              ...row.map((v) => escapeField(v)).join(","),
              ...(EOF || csvData.length - 1 !== i ? [EOL] : []),
            ]),
          ].join("");
          const data = csvData.map((row) =>
            Object.fromEntries(row.map((v, i) => [header[i], v])),
          );
          return { data, csv: new TextEncoder().encode(csv) };
        }),
        async ({ data, csv }) => {
          let i = 0;
          for await (const row of parse(csv)) {
            expect(row).toEqual(data[i++]);
          }
        },
      ),
    ))

Summary: Verifies that parsing a `Uint8Array`-encoded CSV correctly reconstructs the original data structure.


it('should validate school hours correctly', () => {
      fc.assert(
        fc.property(domainArbitraries.validTimeSlot, (timeSlot) => {
          const startValid = isWithinSchoolHours(timeSlot.start);
          const endValid = isWithinSchoolHours(timeSlot.end);

          // Property: Valid time slots should be within school hours
          return startValid && endValid;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Valid time slots should have start and end times within school hours.


it('should handle leap year calculations', () => {
      fc.assert(
        fc.property(fc.integer({ min: 2020, max: 2030 }), (year) => {
          // Property: Leap year detection should be accurate
          const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;

          const feb29 = new Date(year, 1, 29); // February 29
          const isValidDate = feb29.getMonth() === 1 && feb29.getDate() === 29;

          return isLeapYear === isValidDate;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Accurately detects leap years by verifying that February 29th exists only in those years.


it('should handle invalid date inputs gracefully', () => {
      fc.assert(
        fc.property(
          fc.oneof(fc.constant(null), fc.constant(undefined), fc.string(), fc.integer()),
          (invalidInput) => {
            // Property: Date validation should handle invalid inputs
            const validateDate = (input: unknown): boolean => {
              try {
                const date = new Date(input);
                return !isNaN(date.getTime());
              } catch {
                return false;
              }
            };

            const result = validateDate(invalidInput);

            // Should return boolean regardless of input
            return typeof result === 'boolean';
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: `validateDate` returns a boolean when handling various invalid date inputs.


it('should always generate valid curriculum codes', () => {
      fc.assert(
        fc.property(domainArbitraries.curriculumCode, (code) => {
          // Property: All generated codes follow the pattern [A-E][1-5].[1-10]
          const codePattern = /^[A-E][1-5]\.[1-9]|10$/;
          return codePattern.test(code);
        }),
        { numRuns: 50 },
      );
    })

Summary: Generated curriculum codes always match the pattern `[A-E][1-5].[1-10]`.


it('should generate unique codes within reasonable bounds', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.curriculumCode, { minLength: 50, maxLength: 100 }),
          (codes) => {
            // Property: Generated codes should have reasonable diversity
            const uniqueCodes = new Set(codes);
            const uniqueRatio = uniqueCodes.size / codes.length;
            return uniqueRatio > 0.7; // At least 70% unique
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Generated curriculum codes should be at least 70% unique within arrays of length 50 to 100.


it('should maintain grade-subject consistency', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: Grade and subject combinations should be educationally valid
          const validGradeSubjectCombinations = new Map([
            ['Mathematics', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Language Arts', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Science', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Social Studies', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['French', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Physical Education', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Arts', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Music', [1, 2, 3, 4, 5, 6, 7, 8]],
            ['Health', [1, 2, 3, 4, 5, 6, 7, 8]],
          ]);

          const validGrades = validGradeSubjectCombinations.get(expectation.subject) || [];
          return validGrades.includes(expectation.grade);
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Grade-subject combinations should be educationally valid according to predefined mappings.


it('should validate strand-subject relationships', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: Strands should be appropriate for their subjects
          const subjectStrands = new Map([
            [
              'Mathematics',
              ['Number Sense', 'Algebra', 'Geometry', 'Measurement', 'Data Management'],
            ],
            ['Language Arts', ['Reading', 'Writing', 'Oral Communication', 'Media Literacy']],
            [
              'Science',
              [
                'Understanding Life Systems',
                'Understanding Structures and Mechanisms',
                'Understanding Matter and Energy',
                'Understanding Earth and Space Systems',
              ],
            ],
            [
              'Social Studies',
              ['Heritage and Identity', 'People and Environments', 'Citizenship and Government'],
            ],
          ]);

          const validStrands = subjectStrands.get(expectation.subject);
          if (!validStrands) {
            return true; // Unknown subject, skip validation
          }

          return validStrands.includes(expectation.strand);
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Strands should correspond correctly to their associated subjects in curriculum expectations.


it('should maintain English-French content consistency', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: If French content exists, it should be consistent with English
          if (expectation.descriptionFr && expectation.strandFr) {
            // Both descriptions should be non-empty
            const englishValid = expectation.description.trim().length > 0;
            const frenchValid = expectation.descriptionFr.trim().length > 0;
            const englishStrandValid = expectation.strand.trim().length > 0;
            const frenchStrandValid = expectation.strandFr.trim().length > 0;

            return englishValid && frenchValid && englishStrandValid && frenchStrandValid;
          }

          return true; // Skip if no French content
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: If French content is present, both English and French descriptions and strands should be non-empty.


it('should maintain required field constraints', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: Required fields should always be present and valid
          const hasValidId = expectation.id && expectation.id.length > 0;
          const hasValidCode = expectation.code && expectation.code.length > 0;
          const hasValidDescription =
            expectation.description && expectation.description.trim().length > 0;
          const hasValidStrand = expectation.strand && expectation.strand.trim().length > 0;
          const hasValidGrade = expectation.grade >= 1 && expectation.grade <= 8;
          const hasValidSubject = expectation.subject && expectation.subject.length > 0;

          return (
            hasValidId &&
            hasValidCode &&
            hasValidDescription &&
            hasValidStrand &&
            hasValidGrade &&
            hasValidSubject
          );
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The test ensures that all required fields in `fullCurriculumExpectation` have valid and non-empty values and that the grade is between 1 and 8.


it('should preserve data through JSON serialization', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: Serialization should preserve all data
          const serialized = JSON.stringify(expectation);
          const deserialized = JSON.parse(serialized);

          // Compare all fields
          return (
            expectation.id === deserialized.id &&
            expectation.code === deserialized.code &&
            expectation.description === deserialized.description &&
            expectation.strand === deserialized.strand &&
            expectation.grade === deserialized.grade &&
            expectation.subject === deserialized.subject
          );
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Serialization and deserialization using JSON should preserve all fields of a `fullCurriculumExpectation` object, ensuring data integrity.


it('should validate grade progression constraints', () => {
      fc.assert(
        fc.property(domainArbitraries.curriculumProgression, (progression) => {
          // Property: Curriculum complexity should align with grade level
          const { grade, complexity } = progression;

          if (grade <= 3) {
            return complexity === 'basic';
          } else if (grade <= 6) {
            return complexity === 'intermediate';
          } else {
            return complexity === 'advanced';
          }
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Curriculum complexity should match grade level constraints: grades 3 and below must be 'basic', grades 4 to 6 'intermediate', and grades above 6 'advanced'.


it('should limit expectations per grade appropriately', () => {
      fc.assert(
        fc.property(domainArbitraries.curriculumProgression, (progression) => {
          // Property: Lower grades should have fewer expectations
          const { grade, expectations } = progression;

          if (grade <= 3) {
            return expectations.length <= 2;
          } else if (grade <= 6) {
            return expectations.length <= 3;
          } else {
            return expectations.length <= 4;
          }
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Expectations for progressions are limited by grade, with lower grades having fewer expectations.


it('should validate grade-subject alignment correctly', () => {
      fc.assert(
        fc.property(domainArbitraries.grade, domainArbitraries.subject, (grade, subject) => {
          // Property: Valid grade-subject combinations should pass validation
          return validateGradeSubjectAlignment(grade, subject) === true;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Valid grade-subject combinations should result in `validateGradeSubjectAlignment` returning true.


it('should validate expectation content correctly', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: Valid content should pass validation
          return validateExpectationContent(expectation.description, expectation.strand) === true;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Valid curriculum expectation content should pass the validation check.


it('should handle empty and null values gracefully', () => {
      fc.assert(
        fc.property(fc.option(fc.string()), fc.option(fc.string()), (description, strand) => {
          // Property: Validation should handle optional fields appropriately
          const validateOptionalContent = (desc?: string, str?: string): boolean => {
            if (!desc || !str) return false;
            return desc.trim().length > 0 && str.trim().length > 0;
          };

          const result = validateOptionalContent(description || undefined, strand || undefined);

          // If both are provided and non-empty, should be valid
          if (description && strand && description.trim() && strand.trim()) {
            return result === true;
          }
          // If either is missing or empty, should be invalid
          return result === false;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Validation handles optional string fields correctly, ensuring both are non-empty for validity; otherwise, they are invalid.


it('should validate expectations efficiently', () => {
      const startTime = Date.now();

      fc.assert(
        fc.property(
          fc.array(domainArbitraries.fullCurriculumExpectation, { minLength: 100, maxLength: 100 }),
          (expectations) => {
            // Property: Validation should be efficient for large datasets
            const validationStartTime = Date.now();

            expectations.forEach((expectation) => {
              // Simulate validation logic
              const isValid =
                expectation.id.length > 0 &&
                expectation.code.length > 0 &&
                expectation.description.trim().length > 0 &&
                expectation.grade >= 1 &&
                expectation.grade <= 8;
              return isValid;
            });

            const validationTime = Date.now() - validationStartTime;

            // Should validate 100 expectations in less than 100ms
            return validationTime < 100;
          },
        ),
        { ...getPropertyTestConfig('fast'), numRuns: 5 },
      );
    })

Summary: The function checks that validating 100 curriculum expectations takes less than 100 milliseconds, ensuring efficiency for large datasets.


it('should maintain referential integrity in relationships', () => {
    fc.assert(
      fc.property(
        fc.array(domainArbitraries.fullCurriculumExpectation, { minLength: 5, maxLength: 10 }),
        (expectations) => {
          // Property: Related expectations should maintain consistency
          const codeToSubject = new Map<string, string>();

          expectations.forEach((expectation) => {
            const existingSubject = codeToSubject.get(expectation.code);
            if (existingSubject) {
              // If code exists, subject should be consistent
              if (existingSubject !== expectation.subject) {
                return false;
              }
            } else {
              codeToSubject.set(expectation.code, expectation.subject);
            }
          });

          return true;
        },
      ),
      getPropertyTestConfig('fast'),
    );
  })

Summary: Expectations with the same code should consistently map to the same subject within a set.


it('should handle curriculum import scenarios', () => {
    fc.assert(
      fc.property(
        fc.record({
          importId: fc.uuid(),
          expectations: fc.array(domainArbitraries.fullCurriculumExpectation, {
            minLength: 1,
            maxLength: 20,
          }),
          userId: fc.integer({ min: 1, max: 1000 }),
        }),
        (importData) => {
          // Property: Import data should maintain consistency
          const { importId, expectations, userId } = importData;

          // All expectations should be valid
          const allValid = expectations.every(
            (exp) => exp.id && exp.code && exp.description.trim().length > 0,
          );

          // Import should have valid metadata
          const validImport = importId.length > 0 && userId > 0;

          return allValid && validImport;
        },
      ),
      getPropertyTestConfig('fast'),
    );
  })

Summary: Import data should maintain consistency by ensuring all curriculum expectations have valid attributes, and the import has valid metadata.


it('should handle malformed data gracefully', () => {
    fc.assert(
      fc.property(
        fc.record({
          id: fc.option(fc.string()),
          code: fc.option(fc.string()),
          description: fc.option(fc.string()),
          grade: fc.option(fc.integer()),
          subject: fc.option(fc.string()),
        }),
        (malformedData) => {
          // Property: Validation should handle partial/malformed data
          const validatePartialExpectation = (data: unknown): boolean => {
            try {
              // Required fields check
              if (!data.id || !data.code || !data.description || !data.grade || !data.subject) {
                return false;
              }

              // Type checks
              if (
                typeof data.id !== 'string' ||
                typeof data.code !== 'string' ||
                typeof data.description !== 'string' ||
                typeof data.grade !== 'number' ||
                typeof data.subject !== 'string'
              ) {
                return false;
              }

              // Range checks
              if (data.grade < 1 || data.grade > 8) {
                return false;
              }

              return true;
            } catch (_error) {
              return false;
            }
          };

          const result = validatePartialExpectation(malformedData);

          // Should only return true if all required fields are present and valid
          const hasAllFields =
            malformedData.id &&
            malformedData.code &&
            malformedData.description &&
            malformedData.grade &&
            malformedData.subject;

          if (
            hasAllFields &&
            typeof malformedData.grade === 'number' &&
            malformedData.grade >= 1 &&
            malformedData.grade <= 8
          ) {
            return result === true;
          } else {
            return result === false;
          }
        },
      ),
      getPropertyTestConfig('fast'),
    );
  })

Summary: Validation should only return true for data that contains all required fields with correct types and field values within specified ranges; otherwise, it should return false.


it('should maintain valid percentage ranges', () => {
      fc.assert(
        fc.property(domainArbitraries.percentage, (percentage) => {
          // Property: All percentages should be within 0-100 range
          return percentage >= 0 && percentage <= 100;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Percentages should always be within the 0-100 range.


it('should maintain valid rating ranges', () => {
      fc.assert(
        fc.property(domainArbitraries.rating, (rating) => {
          // Property: All ratings should be within 1-5 range
          return rating >= 1 && rating <= 5;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: All ratings should be within the range of 1 to 5.


it('should preserve score ordering', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.percentage, { minLength: 3, maxLength: 10 }),
          (scores) => {
            // Property: Score comparison should be transitive
            const sorted = [...scores].sort((a, b) => a - b);

            for (let i = 2; i < sorted.length; i++) {
              // If A <= B and B <= C, then A <= C
              if (sorted[i - 2] <= sorted[i - 1] && sorted[i - 1] <= sorted[i]) {
                if (sorted[i - 2] > sorted[i]) {
                  return false; // Transitivity violated
                }
              }
            }

            return true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Score ordering should maintain transitivity, ensuring a sorted sequence of percentages doesn't violate transitivity.


it('should convert percentages to achievement levels consistently', () => {
      fc.assert(
        fc.property(domainArbitraries.percentage, (percentage) => {
          // Property: Percentage to achievement level conversion should be deterministic
          const convertToAchievementLevel = (score: number): string => {
            if (score < 50) return 'Below Expectation';
            if (score < 60) return 'Level 1';
            if (score < 70) return 'Level 2';
            if (score < 80) return 'Level 3';
            return 'Level 4';
          };

          const level1 = convertToAchievementLevel(percentage);
          const level2 = convertToAchievementLevel(percentage);

          return level1 === level2; // Should be consistent
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Conversion from percentage to achievement level should be consistent and deterministic.


it('should maintain monotonic achievement level progression', () => {
      fc.assert(
        fc.property(
          fc.tuple(domainArbitraries.percentage, domainArbitraries.percentage),
          ([score1, score2]) => {
            // Property: Higher scores should not result in lower achievement levels
            if (score1 >= score2) {
              const levelToNumber = (level: string): number => {
                switch (level) {
                  case 'Below Expectation':
                    return 0;
                  case 'Level 1':
                    return 1;
                  case 'Level 2':
                    return 2;
                  case 'Level 3':
                    return 3;
                  case 'Level 4':
                    return 4;
                  default:
                    return 0;
                }
              };

              const convertToAchievementLevel = (score: number): string => {
                if (score < 50) return 'Below Expectation';
                if (score < 60) return 'Level 1';
                if (score < 70) return 'Level 2';
                if (score < 80) return 'Level 3';
                return 'Level 4';
              };

              const level1 = convertToAchievementLevel(score1);
              const level2 = convertToAchievementLevel(score2);

              return levelToNumber(level1) >= levelToNumber(level2);
            }

            return true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Higher scores should not result in a lower achievement level.


it('should calculate weighted averages correctly', () => {
      fc.assert(
        fc.property(
          fc.array(
            fc.record({
              score: domainArbitraries.percentage,
              weight: fc.float({ min: 0.1, max: 1.0 }),
            }),
            { minLength: 2, maxLength: 5 },
          ),
          (assessments) => {
            // Property: Weighted average should be within the range of input scores
            const weightedSum = assessments.reduce((sum, a) => sum + a.score * a.weight, 0);
            const totalWeight = assessments.reduce((sum, a) => sum + a.weight, 0);
            const weightedAverage = weightedSum / totalWeight;

            const minScore = Math.min(...assessments.map((a) => a.score));
            const maxScore = Math.max(...assessments.map((a) => a.score));

            return weightedAverage >= minScore && weightedAverage <= maxScore;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The weighted average of assessment scores, considering their weights, should lie within the minimum and maximum score range of the inputs.


it("should parse CSV Response", () =>
    fc.assert(
      fc.asyncProperty(
        fc.gen().map((g) => {
          const header = g(FC.header, {
            fieldConstraints: {
              kindExcludes: ["string16bits"],
            },
          });
          const EOL = g(FC.eol);
          const EOF = g(fc.boolean);
          const csvData = [
            ...g(FC.csvData, {
              rowsConstraints: {
                minLength: 1,
              },
              columnsConstraints: {
                minLength: header.length,
                maxLength: header.length,
              },
              fieldConstraints: {
                kindExcludes: ["string16bits"],
              },
            }),
            // Last row is not empty for testing.
            g(FC.row, {
              fieldConstraints: {
                minLength: 1,
                kindExcludes: ["string16bits"],
              },
              columnsConstraints: {
                minLength: header.length,
                maxLength: header.length,
              },
            }),
          ];
          const csv = [
            header.map((v) => escapeField(v)).join(","),
            EOL,
            ...csvData.flatMap((row, i) => [
              ...row.map((v) => escapeField(v)).join(","),
              ...(EOF || csvData.length - 1 !== i ? [EOL] : []),
            ]),
          ].join("");
          const data = csvData.map((row) =>
            Object.fromEntries(row.map((v, i) => [header[i], v])),
          );
          return {
            data,
            csv: new Response(
              new SingleValueReadableStream(new TextEncoder().encode(csv)),
              { headers: { "content-type": "text/csv" } },
            ),
          };
        }),
        async ({ data, csv }) => {
          let i = 0;
          for await (const row of parse(csv)) {
            expect(row).toEqual(data[i++]);
          }
        },
      ),
    ))

Summary: The `parse` function correctly converts CSV formatted `Response` objects into the expected data structure based on headers and rows.


it('should handle zero weights appropriately', () => {
      fc.assert(
        fc.property(
          fc.array(
            fc.record({
              score: domainArbitraries.percentage,
              weight: fc.constantFrom(0, 0.5, 1.0),
            }),
            { minLength: 3, maxLength: 5 },
          ),
          (assessments) => {
            // Property: Zero-weighted assessments should not affect the average
            const nonZeroAssessments = assessments.filter((a) => a.weight > 0);

            if (nonZeroAssessments.length === 0) {
              return true; // Skip if all weights are zero
            }

            const calculateWeightedAverage = (items: typeof assessments): number => {
              const filteredItems = items.filter((a) => a.weight > 0);
              if (filteredItems.length === 0) return 0;

              const weightedSum = filteredItems.reduce((sum, a) => sum + a.score * a.weight, 0);
              const totalWeight = filteredItems.reduce((sum, a) => sum + a.weight, 0);

              return weightedSum / totalWeight;
            };

            const fullAverage = calculateWeightedAverage(assessments);
            const nonZeroAverage = calculateWeightedAverage(nonZeroAssessments);

            return Math.abs(fullAverage - nonZeroAverage) < 0.001;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Zero-weighted assessments should not impact the calculated average of scores.


it('should calculate simple averages as special case of weighted', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.percentage, { minLength: 2, maxLength: 10 }),
          (scores) => {
            // Property: Equal weights should produce simple average
            const simpleAverage = scores.reduce((sum, score) => sum + score, 0) / scores.length;

            const equalWeightAssessments = scores.map((score) => ({ score, weight: 1 }));
            const weightedSum = equalWeightAssessments.reduce(
              (sum, a) => sum + a.score * a.weight,
              0,
            );
            const totalWeight = equalWeightAssessments.reduce((sum, a) => sum + a.weight, 0);
            const weightedAverage = weightedSum / totalWeight;

            return Math.abs(simpleAverage - weightedAverage) < 0.001;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Calculating a simple average should be equivalent to calculating a weighted average when all weights are equal.


it("should parse a CSV with headers by option", () =>
    fc.assert(
      fc.asyncProperty(
        fc.gen().map((g) => {
          const header = g(FC.header);
          const rows = g(FC.csvData, {
            columnsConstraints: {
              minLength: header.length,
              maxLength: header.length,
            },
          });
          const tokens = [
            ...rows.flatMap<Token>((row) =>
              row.flatMap<Token>((field, j) => [
                { type: Field, value: field, location: LOCATION_SHAPE },
                {
                  type: FieldDelimiter,
                  value: ",",
                  location: LOCATION_SHAPE,
                },
                ...((j === row.length - 1
                  ? [
                      {
                        type: RecordDelimiter,
                        value: "\n",
                      },
                    ]
                  : []) as Token[]),
              ]),
            ),
          ];
          const expected = rows.map((row) =>
            Object.fromEntries(row.map((field, i) => [header[i], field])),
          );
          return { header, tokens, expected };
        }),
        async ({ header, tokens, expected }) => {
          const parser = new RecordAssemblerTransformer({
            header,
          });
          const actual = await transform(parser, [tokens]);
          expect(actual).toEqual(expected);
        },
      ),
    ))

Summary: A CSV with headers specified by the option should be parsed into an array of objects, where each object maps header fields to their corresponding row values.


it('should maintain valid assessment distribution ratios', () => {
      fc.assert(
        fc.property(domainArbitraries.assessmentDistribution, (distribution) => {
          // Property: Assessment distribution should sum correctly and maintain ratios
          const { diagnostic, formative, summative, total } = distribution;

          const calculatedTotal = diagnostic + formative + summative;
          const validTotal = calculatedTotal === total;

          const validRatios = diagnostic >= 0 && formative >= 0 && summative >= 0 && total > 0;

          return validTotal && validRatios;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The assessment distribution should correctly sum to the total and maintain non-negative ratios.


it('should recommend appropriate assessment balance', () => {
      fc.assert(
        fc.property(
          domainArbitraries.grade,
          domainArbitraries.assessmentDistribution,
          (grade, distribution) => {
            // Property: Assessment balance should be appropriate for grade level
            const { formative, summative, total } = distribution;

            const formativeRatio = formative / total;
            const summativeRatio = summative / total;

            if (grade <= 3) {
              // Lower grades should emphasize formative assessment
              return formativeRatio >= 0.6 && summativeRatio <= 0.3;
            } else if (grade <= 6) {
              // Middle grades should have balanced assessment
              return formativeRatio >= 0.5 && summativeRatio <= 0.4;
            } else {
              // Upper grades can have more summative assessment
              return formativeRatio >= 0.4 && summativeRatio <= 0.5;
            }
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Assessment balance should be appropriate for the grade level, with varying emphasis on formative and summative assessments depending on whether the grade is lower, middle, or upper.


it('should calculate standard deviation correctly', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.percentage, { minLength: 5, maxLength: 20 }),
          (scores) => {
            // Property: Standard deviation should be non-negative and bounded
            const mean = scores.reduce((sum, score) => sum + score, 0) / scores.length;
            const variance =
              scores.reduce((sum, score) => sum + Math.pow(score - mean, 2), 0) / scores.length;
            const stdDev = Math.sqrt(variance);

            // Standard deviation should be non-negative
            const nonNegative = stdDev >= 0;

            // Standard deviation should not exceed the range of scores
            const minScore = Math.min(...scores);
            const maxScore = Math.max(...scores);
            const maxPossibleStdDev = (maxScore - minScore) / 2; // Theoretical maximum

            return nonNegative && stdDev <= maxPossibleStdDev + 1; // +1 for floating point tolerance
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The standard deviation calculated from an array of percentage scores should be non-negative and not exceed a certain bounded maximum value.


it('should identify outliers consistently', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.percentage, { minLength: 10, maxLength: 20 }),
          (scores) => {
            // Property: Outlier detection should be consistent
            const identifyOutliers = (data: number[]): number[] => {
              const sorted = [...data].sort((a, b) => a - b);
              const q1Index = Math.floor(sorted.length * 0.25);
              const q3Index = Math.floor(sorted.length * 0.75);

              const q1 = sorted[q1Index];
              const q3 = sorted[q3Index];
              const iqr = q3 - q1;

              const lowerBound = q1 - 1.5 * iqr;
              const upperBound = q3 + 1.5 * iqr;

              return data.filter((score) => score < lowerBound || score > upperBound);
            };

            const outliers1 = identifyOutliers(scores);
            const outliers2 = identifyOutliers(scores);

            // Should be consistent
            return outliers1.length === outliers2.length;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Identifies outliers consistently by ensuring repeated calls produce identical results.


it('should calculate percentiles correctly', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.percentage, { minLength: 10, maxLength: 50 }),
          fc.integer({ min: 1, max: 99 }),
          (scores, percentile) => {
            // Property: Percentiles should be monotonically increasing
            const calculatePercentile = (data: number[], p: number): number => {
              const sorted = [...data].sort((a, b) => a - b);
              const index = (p / 100) * (sorted.length - 1);
              const lower = Math.floor(index);
              const upper = Math.ceil(index);

              if (lower === upper) {
                return sorted[lower];
              }

              const weight = index - lower;
              return sorted[lower] * (1 - weight) + sorted[upper] * weight;
            };

            const lowerPercentile = calculatePercentile(scores, Math.max(1, percentile - 10));
            const currentPercentile = calculatePercentile(scores, percentile);
            const upperPercentile = calculatePercentile(scores, Math.min(99, percentile + 10));

            return lowerPercentile <= currentPercentile && currentPercentile <= upperPercentile;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Percentiles calculated from a list of scores should be monotonically increasing as the percentile value increases.


it('should maintain rubric score consistency', () => {
      fc.assert(
        fc.property(
          fc.array(
            fc.record({
              criterion: fc.string({ minLength: 5, maxLength: 20 }),
              score: domainArbitraries.rating,
              weight: fc.float({ min: 0.1, max: 1.0 }),
            }),
            { minLength: 3, maxLength: 6 },
          ),
          (rubricItems) => {
            // Property: Rubric total should be weighted average of criteria
            const weightedSum = rubricItems.reduce(
              (sum, item) => sum + item.score * item.weight,
              0,
            );
            const totalWeight = rubricItems.reduce((sum, item) => sum + item.weight, 0);
            const rubricScore = weightedSum / totalWeight;

            const minScore = Math.min(...rubricItems.map((item) => item.score));
            const maxScore = Math.max(...rubricItems.map((item) => item.score));

            return rubricScore >= minScore && rubricScore <= maxScore;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The weighted average score of rubric items should be between the minimum and maximum individual scores of those items.


it('should handle missing criterion scores appropriately', () => {
      fc.assert(
        fc.property(
          fc.array(
            fc.record({
              criterion: fc.string({ minLength: 5, maxLength: 20 }),
              score: fc.option(domainArbitraries.rating),
              weight: fc.float({ min: 0.1, max: 1.0 }),
            }),
            { minLength: 3, maxLength: 6 },
          ),
          (rubricItems) => {
            // Property: Missing scores should not break calculation
            const validItems = rubricItems.filter(
              (item) => item.score !== null && item.score !== undefined,
            );

            if (validItems.length === 0) {
              return true; // Skip if no valid scores
            }

            const calculateRubricScore = (items: typeof validItems): number => {
              const weightedSum = items.reduce((sum, item) => sum + item.score! * item.weight, 0);
              const totalWeight = items.reduce((sum, item) => sum + item.weight, 0);
              return weightedSum / totalWeight;
            };

            const score = calculateRubricScore(validItems);

            return score >= 1 && score <= 5; // Should be within rating range
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The calculation should correctly handle rubric items with missing scores, ensuring the resulting score is within a specified range when computed only from valid scores.


it('should track learning progression over time', () => {
      fc.assert(
        fc.property(
          fc.array(
            fc.record({
              date: fc.date({ min: new Date('2024-01-01'), max: new Date('2024-12-31') }),
              score: domainArbitraries.percentage,
              expectationId: fc.uuid(),
            }),
            { minLength: 5, maxLength: 15 },
          ),
          (progressEntries) => {
            // Property: Progress tracking should show consistent trends
            const entriesByExpectation = new Map<string, typeof progressEntries>();

            progressEntries.forEach((entry) => {
              if (!entriesByExpectation.has(entry.expectationId)) {
                entriesByExpectation.set(entry.expectationId, []);
              }
              entriesByExpectation.get(entry.expectationId)!.push(entry);
            });

            // Check each expectation's progress
            for (const [, entries] of entriesByExpectation) {
              if (entries.length < 2) continue;

              // Sort by date
              const sortedEntries = entries.sort((a, b) => a.date.getTime() - b.date.getTime());

              // Calculate trend
              const firstScore = sortedEntries[0].score;
              const lastScore = sortedEntries[sortedEntries.length - 1].score;

              // Trend should be reasonable (not impossible jumps)
              const scoreDifference = Math.abs(lastScore - firstScore);
              if (scoreDifference > 80) {
                return false; // Unrealistic score change
              }
            }

            return true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Tracking learning progression should show consistent trends over time without unrealistic score jumps for each expectation.


it('should calculate improvement rates correctly', () => {
      fc.assert(
        fc.property(
          fc.array(
            fc.record({
              week: fc.integer({ min: 1, max: 40 }),
              score: domainArbitraries.percentage,
            }),
            { minLength: 4, maxLength: 10 },
          ),
          (weeklyScores) => {
            // Property: Improvement rate calculation should be consistent
            const sortedScores = weeklyScores.sort((a, b) => a.week - b.week);

            if (sortedScores.length < 2) return true;

            const calculateImprovementRate = (scores: typeof sortedScores): number => {
              const firstScore = scores[0].score;
              const lastScore = scores[scores.length - 1].score;
              const weeksDifference = scores[scores.length - 1].week - scores[0].week;

              if (weeksDifference === 0) return 0;

              return (lastScore - firstScore) / weeksDifference;
            };

            const improvementRate = calculateImprovementRate(sortedScores);

            // Improvement rate should be bounded
            return Math.abs(improvementRate) <= 25; // Max 25 points per week
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Calculates improvement rates from weekly scores, ensuring the rate is consistent and bounded within a maximum of 25 points per week.


it('should handle grade boundary edge cases', () => {
      fc.assert(
        fc.property(
          fc.float({ min: 49.8, max: 50.2 }), // Around 50% boundary
          (score) => {
            // Property: Scores near boundaries should be handled consistently
            const getGradeBoundary = (percentage: number): string => {
              if (percentage < 50) return 'Below Standard';
              if (percentage < 60) return 'Approaching Standard';
              if (percentage < 70) return 'Meeting Standard';
              if (percentage < 80) return 'Exceeding Standard';
              return 'Outstanding';
            };

            const grade1 = getGradeBoundary(score);
            const grade2 = getGradeBoundary(score);

            // Should be consistent
            return grade1 === grade2;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Grades should be consistently determined for scores near the 50% boundary edge case.


it('should apply grade boundaries fairly', () => {
      fc.assert(
        fc.property(
          fc.tuple(domainArbitraries.percentage, domainArbitraries.percentage),
          ([score1, score2]) => {
            // Property: Higher scores should not result in lower grades
            const getGradeLevel = (percentage: number): number => {
              if (percentage < 50) return 1;
              if (percentage < 60) return 2;
              if (percentage < 70) return 3;
              if (percentage < 80) return 4;
              return 5;
            };

            const grade1 = getGradeLevel(score1);
            const grade2 = getGradeLevel(score2);

            if (score1 >= score2) {
              return grade1 >= grade2;
            }

            return true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Higher scores should not result in lower grades based on specified grade boundaries.


it('should handle assessment data validation', () => {
      fc.assert(
        fc.property(
          fc.record({
            studentId: fc.option(fc.uuid()),
            assessmentId: fc.uuid(),
            score: fc.option(domainArbitraries.percentage),
            submittedAt: fc.option(fc.date()),
            attempt: fc.integer({ min: 1, max: 5 }),
          }),
          (assessmentData) => {
            // Property: Assessment validation should handle incomplete data
            const validateAssessmentData = (data: typeof assessmentData): boolean => {
              // Required fields check
              if (!data.assessmentId) return false;

              // Score validation
              if (data.score !== null && data.score !== undefined) {
                if (data.score < 0 || data.score > 100) return false;
              }

              // Attempt validation
              if (data.attempt < 1 || data.attempt > 5) return false;

              return true;
            };

            const isValid = validateAssessmentData(assessmentData);

            // Should return boolean result
            return typeof isValid === 'boolean';
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Assessment data validation must correctly handle incomplete data and meet field-specific requirements, ensuring a boolean result.


it('should maintain arithmetic properties in calculations', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.percentage, { minLength: 3, maxLength: 8 }),
          (scores) => {
            // Property: Addition should be commutative
            const sum1 = scores.reduce((sum, score) => sum + score, 0);
            const sum2 = [...scores].reverse().reduce((sum, score) => sum + score, 0);

            return Math.abs(sum1 - sum2) < 0.001; // Account for floating point precision
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The test checks that the sum of an array of percentage scores remains consistent when the order of addition is reversed, verifying the commutative property of addition.


it('should handle floating point precision in calculations', () => {
      fc.assert(
        fc.property(
          fc.array(fc.float({ min: 0, max: 100 }), { minLength: 3, maxLength: 10 }),
          (scores) => {
            // Property: Calculations should handle floating point precision
            const average1 = scores.reduce((sum, score) => sum + score, 0) / scores.length;

            // Recalculate using a different method
            let sum = 0;
            for (const score of scores) {
              sum += score;
            }
            const average2 = sum / scores.length;

            // Should be equal within floating point tolerance
            return Math.abs(average1 - average2) < 0.0001;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Calculations of averages should maintain floating point precision, ensuring results from different summation methods are equal within a small tolerance.


it('should maintain consistency in rounding operations', () => {
      fc.assert(
        fc.property(
          fc.float({ min: 0, max: 100 }),
          fc.integer({ min: 0, max: 3 }), // decimal places
          (score, decimals) => {
            // Property: Rounding should be consistent
            const roundToDecimals = (num: number, places: number): number => {
              const factor = Math.pow(10, places);
              return Math.round(num * factor) / factor;
            };

            const rounded1 = roundToDecimals(score, decimals);
            const rounded2 = roundToDecimals(score, decimals);

            return rounded1 === rounded2;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Rounding a floating-point number to a specified number of decimal places should consistently yield the same result.


it("should lex with with user given quotation and delimiter", () => {
    fc.assert(
      fc.property(
        fc.gen().map((g) => {
          const options = g(FC.commonOptions);
          const row = g(FC.row);
          const csv = row
            .map((field) => escapeField(field, options))
            .join(options.delimiter);
          const expected = [
            ...row.flatMap((field, i) => [
              // if field is empty or field is escaped, it should be escaped.
              ...(field !== "" || escapeField(field, options) !== field
                ? [{ type: Field, value: field, location: LOCATION_SHAPE }]
                : []),
              // if field is not last field, it should be followed by a field delimiter
              ...(row.length - 1 !== i
                ? [
                    {
                      type: FieldDelimiter,
                      value: options.delimiter,
                      location: LOCATION_SHAPE,
                    },
                  ]
                : []),
            ]),
          ];
          return { options, row, csv, expected };
        }),
        ({ options, csv, expected }) => {
          const lexer = new Lexer(options);
          const actual = [...lexer.lex(csv)];
          expect(actual).toMatchObject(expected);
        },
      ),
    );
  })

Summary: Lexing a CSV string with user-defined quotation and delimiter options should produce tokens matching the expected fields and delimiters.


it('should apply late penalty calculations correctly', () => {
      fc.assert(
        fc.property(
          domainArbitraries.percentage,
          fc.integer({ min: 1, max: 10 }), // days late
          fc.float({ min: 0.05, max: 0.2 }), // penalty rate
          (originalScore, daysLate, penaltyRate) => {
            // Property: Late penalties should reduce scores appropriately
            const applyLatePenalty = (score: number, days: number, rate: number): number => {
              const penalty = score * rate * days;
              return Math.max(0, score - penalty); // Cannot go below 0
            };

            const penalizedScore = applyLatePenalty(originalScore, daysLate, penaltyRate);

            // Penalized score should be less than or equal to original
            const validPenalty = penalizedScore <= originalScore;

            // Should not go below 0
            const validRange = penalizedScore >= 0 && penalizedScore <= 100;

            return validPenalty && validRange;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Late penalty calculations should reduce scores appropriately without lowering them below zero, ensuring penalized scores remain between 0 and the original score.


it('should handle extra credit calculations appropriately', () => {
      fc.assert(
        fc.property(
          domainArbitraries.percentage,
          fc.float({ min: 0, max: 10 }), // extra credit points
          (baseScore, extraCredit) => {
            // Property: Extra credit should not exceed reasonable limits
            const applyExtraCredit = (score: number, extra: number): number => {
              const newScore = score + extra;
              return Math.min(105, newScore); // Cap at 105%
            };

            const finalScore = applyExtraCredit(baseScore, extraCredit);

            // Should be greater than or equal to base score
            const validIncrease = finalScore >= baseScore;

            // Should not exceed 105%
            const validCap = finalScore <= 105;

            return validIncrease && validCap;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Extra credit calculations should result in final scores that are no less than the base score and do not exceed a maximum of 105%.


it('should test array properties', () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        // Property: Array concat with empty array returns same array
        const result = arr.concat([]);
        return result.length === arr.length;
      }),
      { numRuns: 50 },
    );
  })

Summary: Concatenating an integer array with an empty array returns an array of the same length.


it('should ensure lessons fit within school hours', () => {
      fc.assert(
        fc.property(domainArbitraries.validTimeSlot, (timeSlot) => {
          // Property: All scheduled lessons must fit within school hours (8 AM - 4 PM)
          const schoolStart = 8; // 8 AM
          const schoolEnd = 16; // 4 PM

          const startHour = timeSlot.start.getHours();
          const endHour = timeSlot.end.getHours();
          const endMinute = timeSlot.end.getMinutes();

          // Lesson should start after school starts and end before school ends
          const startsAfterSchoolStart = startHour >= schoolStart;
          const endsBeforeSchoolEnd =
            endHour < schoolEnd || (endHour === schoolEnd && endMinute === 0);

          return startsAfterSchoolStart && endsBeforeSchoolEnd;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Scheduled lessons must start at or after 8 AM and end by or before 4 PM, aligning with school hours.


it('should maintain positive lesson durations', () => {
      fc.assert(
        fc.property(domainArbitraries.validTimeSlot, (timeSlot) => {
          // Property: Lesson duration should always be positive
          const durationMs = timeSlot.end.getTime() - timeSlot.start.getTime();
          const durationMinutes = durationMs / (1000 * 60);

          return durationMinutes > 0 && durationMinutes === timeSlot.duration;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The lesson duration calculated from `timeSlot` should always be positive and match `timeSlot.duration`.


test('Difference in days', () => {
  fc.assert(
    fc.property(
      fcCalendarDate(),
      fc.integer(-2000 * 365, 2000 * 365),
      (date, days) => {
        const laterDay = addDays(date, days);
        const diff = numberOfDaysBetween({ start: date, end: laterDay });
        expect(diff).toBe(days);
      },
    ),
  );
})

Summary: The number of days calculated between two dates should equal the number of days added to the initial date.


test('Add days', () => {
  fc.assert(
    fc.property(fcCalendarDate(), fcCalendarDate(), (a, b) => {
      const diff = numberOfDaysBetween({ start: a, end: b });

      const bPrime = addDays(a, diff);
      expect(bPrime).toEqual(b);

      const aPrime = addDays(b, -diff);
      expect(aPrime).toEqual(a);
    }),
  );
})

Summary: Adding a calculated number of days between two dates to one date should result in the other date, and vice versa when subtracting.


test('Adding days sequentially', () => {
  fc.assert(
    fc.property(fcCalendarDate(), fc.integer(-100, 100), (date, n) => {
      const otherDate = addDays(date, n);
      const step = n < 0 ? -1 : 1;
      const otherDatePrime = repeat(Math.abs(n), (d) => addDays(d, step), date);
      expect(otherDate).toEqual(otherDatePrime);
    }),
  );
})

Summary: Adding days sequentially to a date should yield the same result as adding them one at a time repeatedly.


it('should respect minimum and maximum lesson durations', () => {
      fc.assert(
        fc.property(domainArbitraries.lessonDuration, (duration) => {
          // Property: Lesson durations should be within pedagogically sound ranges
          const minDuration = 15; // 15 minutes minimum
          const maxDuration = 120; // 2 hours maximum

          return duration >= minDuration && duration <= maxDuration;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Lesson durations should fall within the range of 15 to 120 minutes.


it('should detect overlapping lessons', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.validTimeSlot, { minLength: 2, maxLength: 10 }),
          (timeSlots) => {
            // Property: No two lessons should overlap in time
            const hasOverlap = (
              slot1: (typeof timeSlots)[0],
              slot2: (typeof timeSlots)[0],
            ): boolean => {
              return (
                (slot1.start <= slot2.start && slot1.end > slot2.start) ||
                (slot2.start <= slot1.start && slot2.end > slot1.start)
              );
            };

            const detectConflicts = (slots: typeof timeSlots): boolean => {
              for (let i = 0; i < slots.length; i++) {
                for (let j = i + 1; j < slots.length; j++) {
                  if (hasOverlap(slots[i], slots[j])) {
                    return true; // Conflict found
                  }
                }
              }
              return false; // No conflicts
            };

            // Property: Conflict detection should work correctly
            return typeof detectConflicts(timeSlots) === 'boolean';
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Detects if there are overlapping lessons in a set of time slots, ensuring conflict detection returns a boolean.


test('Number of days in leapyears', () => {
  fc.assert(
    fc.property(fcCalendarDate(), (date) => {
      const startOfYear: CalendarDate = { ...date, month: 'jan', day: 1 };
      const endOfYear: CalendarDate = { ...date, month: 'dec', day: 31 };
      const allDaysInYear = periodOfDates(startOfYear, endOfYear);
      const numberOfDays =
        numberOfDaysBetween({ start: startOfYear, end: endOfYear }) + 1;
      const numberOfDaysInSuchAYear = isLeapYear(date) ? 366 : 365;
      expect(allDaysInYear.length).toBe(numberOfDaysInSuchAYear);
      expect(numberOfDays).toBe(numberOfDaysInSuchAYear);
    }),
  );
})

Summary: The number of days in a year, generated from a start and end date, should match 366 for leap years or 365 for non-leap years.


it('should handle adjacent lessons correctly', () => {
      fc.assert(
        fc.property(
          domainArbitraries.validTimeSlot,
          domainArbitraries.lessonDuration,
          (firstSlot, secondDuration) => {
            // Property: Adjacent lessons (end time = start time) should not conflict
            const secondSlot = {
              start: new Date(firstSlot.end.getTime()),
              end: new Date(firstSlot.end.getTime() + secondDuration * 60 * 1000),
              duration: secondDuration,
            };

            // Check if second lesson would extend beyond school hours
            const schoolEnd = new Date(firstSlot.start);
            schoolEnd.setHours(16, 0, 0, 0);

            if (secondSlot.end > schoolEnd) {
              return true; // Skip if would extend beyond school hours
            }

            // Adjacent lessons should not be considered overlapping
            const areAdjacent = firstSlot.end.getTime() === secondSlot.start.getTime();
            const doNotOverlap =
              firstSlot.end <= secondSlot.start || secondSlot.end <= firstSlot.start;

            return areAdjacent ? doNotOverlap : true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Adjacent lessons where the end time of the first lesson equals the start time of the second lesson should not be considered overlapping, provided the second lesson does not extend beyond school hours.


test('Period of dates has correct number of days', () => {
  fc.assert(
    fc.property(fcCalendarDate(), fcCalendarDate(), (a, b) => {
      const daysBetween = numberOfDaysBetween({ start: a, end: b }) + 1;
      if (Math.abs(daysBetween) > 1000) {
        return;
      }
      const allDaysInPeriod = periodOfDates(a, b);
      expect(allDaysInPeriod.length).toBe(Math.max(daysBetween, 0));
    }),
  );
})

Summary: The period of dates calculated should have a length equal to the computed number of days between two dates, accounting for a maximum of 1000 days.


test('Ordered ints', () => {
  fc.assert(
    fc.property(
      fcCalendarDate(),
      fc.array(fc.integer(-100, 100)),
      (date, ints) => {
        const orderedInts = ints.sort((a, b) => a - b);
        const shiftDays = (n: number) => addDays(date, n);
        const dates = orderedInts.map(shiftDays);
        expect(areInOrder(...dates)).toBe(true);
      },
    ),
  );
})

Summary: `areInOrder` should return true when dates are generated by adding ordered integers to a given date.


it('should maintain daily time limits', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.fullLessonPlan, { minLength: 1, maxLength: 8 }),
          (dailyLessons) => {
            // Property: Total daily lesson time should not exceed school day limits
            const maxDailyMinutes = 7 * 60; // 7 hours max per day

            // Group lessons by date
            const lessonsByDate = new Map<string, typeof dailyLessons>();
            dailyLessons.forEach((lesson) => {
              const dateKey = lesson.date.toISOString().split('T')[0];
              if (!lessonsByDate.has(dateKey)) {
                lessonsByDate.set(dateKey, []);
              }
              lessonsByDate.get(dateKey)!.push(lesson);
            });

            // Check each day's total duration
            for (const [, lessons] of lessonsByDate) {
              const totalDuration = lessons.reduce((sum, lesson) => sum + lesson.duration, 0);
              if (totalDuration > maxDailyMinutes) {
                return false;
              }
            }

            return true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Total daily lesson time for grouped lessons by date should not exceed 7 hours.


test('Serialize', () => {
  fc.assert(
    fc.property(fcCalendarDate(), (date) => {
      const serialized = serializeIso8601String(date);

      expect(serialized.length).toBe(10);

      const yyyymmdd = /^\d{4}-\d{2}-\d{2}$/;
      expect(yyyymmdd.test(serialized)).toBe(true);

      const digitsOrDash = /^[0-9\-]*$/;
      expect(digitsOrDash.test(serialized)).toBe(true);
    }),
  );
})

Summary: Serialization of a calendar date should result in a 10-character ISO 8601 string in the format YYYY-MM-DD, containing only digits and dashes.


it('should balance subject distribution across the week', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.fullLessonPlan, { minLength: 10, maxLength: 25 }),
          (weeklyLessons) => {
            // Property: Core subjects should appear multiple times per week
            const subjectCounts = new Map<string, number>();

            weeklyLessons.forEach((lesson) => {
              subjectCounts.set(lesson.subject, (subjectCounts.get(lesson.subject) || 0) + 1);
            });

            const coreSubjects = ['Mathematics', 'Language Arts'];
            const hasBalancedCore = coreSubjects.every((subject) => {
              const count = subjectCounts.get(subject) || 0;
              return count >= 3; // At least 3 lessons per week for core subjects
            });

            // If we have enough lessons for a full week, check balance
            if (weeklyLessons.length >= 15) {
              return hasBalancedCore;
            }

            return true; // Skip check for smaller lesson sets
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Core subjects, specifically 'Mathematics' and 'Language Arts', should appear at least three times per week in lesson plans with a minimum of 15 lessons.


it('should maintain realistic unit durations', () => {
      fc.assert(
        fc.property(domainArbitraries.unitTimeline, (timeline) => {
          // Property: Unit timelines should be educationally realistic
          const { startDate, endDate, totalHours, lessonCount, averageLessonDuration } = timeline;

          // Duration checks
          const durationMs = endDate.getTime() - startDate.getTime();
          const durationDays = durationMs / (1000 * 60 * 60 * 24);
          const durationWeeks = durationDays / 7;

          // Unit should be 1-8 weeks long
          const validDuration = durationWeeks >= 1 && durationWeeks <= 8;

          // Average lesson duration should be reasonable (30-90 minutes)
          const validAverageDuration = averageLessonDuration >= 30 && averageLessonDuration <= 90;

          // Lesson count should align with duration (3-5 lessons per week)
          const expectedLessonsPerWeek = Math.round(lessonCount / durationWeeks);
          const validLessonFrequency = expectedLessonsPerWeek >= 3 && expectedLessonsPerWeek <= 5;

          return validDuration && validAverageDuration && validLessonFrequency;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Unit timelines should have a duration of 1-8 weeks, average lesson durations of 30-90 minutes, and 3-5 lessons per week.


test('Adding more than a year of days', () => {
  fc.assert(
    fc.property(fcCalendarDate(), fc.integer(-2000, 2000), (date, n) => {
      const otherDate = addDays(date, n);
      if (Math.abs(n) >= 366) {
        expect(date.year !== otherDate.year).toBe(true);
      }
    }),
  );
})

Summary: Adding more than 365 days to a date should result in a different year.


test('Associativity', () => {
  fc.assert(
    fc.property(
      fcCalendarDate(),
      fc.integer(-500 * 365, 500 * 365),
      fc.integer(-500 * 365, 500 * 365),
      (date, x, y) => {
        expect(addDays(date, x + y)).toEqual(addDays(addDays(date, x), y));
      },
    ),
  );
})

Summary: Adding days to a date should be associative, meaning `addDays(date, x + y)` should equal `addDays(addDays(date, x), y)`.


it('should ensure lessons fit within unit timeframe', () => {
      fc.assert(
        fc.property(
          domainArbitraries.unitTimeline,
          fc.array(domainArbitraries.fullLessonPlan, { minLength: 1, maxLength: 15 }),
          (timeline, unitLessons) => {
            // Property: All unit lessons should fall within unit start/end dates
            const { startDate, endDate } = timeline;

            // Adjust lesson dates to fall within unit timeframe
            const adjustedLessons = unitLessons.map((lesson, index) => {
              const totalDays = (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24);
              const dayOffset = Math.floor((index / unitLessons.length) * totalDays);
              const lessonDate = new Date(startDate.getTime() + dayOffset * 24 * 60 * 60 * 1000);

              return {
                ...lesson,
                date: lessonDate,
              };
            });

            // Verify all lessons fall within unit timeframe
            return adjustedLessons.every(
              (lesson) => lesson.date >= startDate && lesson.date <= endDate,
            );
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Lessons are adjusted to fit within the unit's start and end dates, ensuring all lessons fall within this timeframe.


it('should handle resource conflicts', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.fullLessonPlan, { minLength: 2, maxLength: 5 }),
          domainArbitraries.technology,
          (lessons, sharedResource) => {
            // Property: Shared resources should not be double-booked
            const lessonsWithResource = lessons.map((lesson) => ({
              ...lesson,
              materials: [...lesson.materials, sharedResource],
            }));

            // Check for same-time resource conflicts
            const hasResourceConflict = (): boolean => {
              for (let i = 0; i < lessonsWithResource.length; i++) {
                for (let j = i + 1; j < lessonsWithResource.length; j++) {
                  const lesson1 = lessonsWithResource[i];
                  const lesson2 = lessonsWithResource[j];

                  // If same date and both use the shared resource
                  if (lesson1.date.toDateString() === lesson2.date.toDateString()) {
                    const end1 = new Date(lesson1.date.getTime() + lesson1.duration * 60 * 1000);
                    const end2 = new Date(lesson2.date.getTime() + lesson2.duration * 60 * 1000);

                    // Check for time overlap
                    if (
                      (lesson1.date <= lesson2.date && end1 > lesson2.date) ||
                      (lesson2.date <= lesson1.date && end2 > lesson1.date)
                    ) {
                      return true;
                    }
                  }
                }
              }
              return false;
            };

            // Property: System should detect resource conflicts
            return typeof hasResourceConflict() === 'boolean';
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The system should correctly detect conflicts when shared resources are double-booked in overlapping lesson schedules.


it('should allow for transitions between lessons', () => {
      fc.assert(
        fc.property(
          fc.tuple(domainArbitraries.validTimeSlot, domainArbitraries.validTimeSlot),
          ([slot1, slot2]) => {
            // Property: Consecutive lessons should have transition time
            const minTransitionMinutes = 5;

            // If lessons are on the same day
            if (slot1.start.toDateString() === slot2.start.toDateString()) {
              // Ensure they don't overlap and have transition time
              if (slot1.end <= slot2.start) {
                const transitionMs = slot2.start.getTime() - slot1.end.getTime();
                const transitionMinutes = transitionMs / (1000 * 60);
                return transitionMinutes >= minTransitionMinutes;
              } else if (slot2.end <= slot1.start) {
                const transitionMs = slot1.start.getTime() - slot2.end.getTime();
                const transitionMinutes = transitionMs / (1000 * 60);
                return transitionMinutes >= minTransitionMinutes;
              } else {
                return false; // Overlapping lessons
              }
            }

            return true; // Different days, no conflict
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Consecutive lessons within the same day must have a transition time of at least five minutes, ensuring non-overlapping schedules.


it('should include adequate lunch and recess breaks', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.validTimeSlot, { minLength: 4, maxLength: 8 }),
          (dailySlots) => {
            // Property: Daily schedule should allow for lunch and recess

            // Sort slots by start time
            const sortedSlots = [...dailySlots].sort(
              (a, b) => a.start.getTime() - b.start.getTime(),
            );

            // Check for gaps that could accommodate breaks
            let hasLunchBreak = false;
            let hasRecessBreak = false;

            for (let i = 0; i < sortedSlots.length - 1; i++) {
              const currentEnd = sortedSlots[i].end;
              const nextStart = sortedSlots[i + 1].start;
              const gapMinutes = (nextStart.getTime() - currentEnd.getTime()) / (1000 * 60);

              // Lunch break: 30+ minutes around 11:30-1:00
              const currentHour = currentEnd.getHours();
              if (gapMinutes >= 30 && currentHour >= 11 && currentHour <= 13) {
                hasLunchBreak = true;
              }

              // Recess break: 15+ minutes around 10:00-10:30 or 2:00-2:30
              if (
                gapMinutes >= 15 &&
                ((currentHour >= 10 && currentHour <= 10) ||
                  (currentHour >= 14 && currentHour <= 14))
              ) {
                hasRecessBreak = true;
              }
            }

            // For a full day (6+ lessons), should have both breaks
            if (sortedSlots.length >= 6) {
              return hasLunchBreak && hasRecessBreak;
            }

            return true; // Partial day, less stringent requirements
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Daily schedules must include at least a 30-minute lunch break and a 15-minute recess break if they have 6 or more lessons.


it('should distribute assessments appropriately', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.fullLessonPlan, { minLength: 10, maxLength: 20 }),
          (lessons) => {
            // Property: Assessments should be well-distributed throughout the unit
            const assessmentLessons = lessons.filter(
              (lesson) => lesson.assessmentType === 'summative',
            );

            if (assessmentLessons.length === 0) {
              return true; // No assessments to check
            }

            // Sort by date
            const sortedAssessments = assessmentLessons.sort(
              (a, b) => a.date.getTime() - b.date.getTime(),
            );

            // Check spacing between assessments
            for (let i = 0; i < sortedAssessments.length - 1; i++) {
              const daysBetween =
                Math.abs(
                  sortedAssessments[i + 1].date.getTime() - sortedAssessments[i].date.getTime(),
                ) /
                (1000 * 60 * 60 * 24);

              // Should have at least 3 days between major assessments
              if (daysBetween < 3) {
                return false;
              }
            }

            return true;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Assessments labeled as 'summative' within a lesson plan should have at least three days between their scheduled dates.


it('should identify substitute-friendly lessons', () => {
      fc.assert(
        fc.property(domainArbitraries.fullLessonPlan, (lesson) => {
          // Property: Substitute-friendly lessons should have specific characteristics
          const isSubFriendly =
            lesson.assessmentType !== 'summative' &&
            lesson.materials.every(
              (material) => !['computer', 'tablet', 'projector'].includes(material),
            );

          // Complex activities are typically not sub-friendly
          const hasComplexActivities =
            (lesson.action && lesson.action.toLowerCase().includes('experiment')) ||
            (lesson.action && lesson.action.toLowerCase().includes('investigation'));

          if (hasComplexActivities) {
            return !isSubFriendly; // Should not be marked as sub-friendly
          }

          return true; // Other lessons can be either way
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Determines whether lessons marked as substitute-friendly lack summative assessments, avoid reliance on certain materials, and do not include complex activities.


it('should maintain schedule optimization properties', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.fullLessonPlan, { minLength: 5, maxLength: 15 }),
          (lessons) => {
            // Property: Optimized schedule should minimize context switching

            // Sort lessons by date and time
            const sortedLessons = [...lessons].sort((a, b) => a.date.getTime() - b.date.getTime());

            // Count subject changes within the same day
            let subjectChanges = 0;
            const lessonsByDay = new Map<string, typeof lessons>();

            sortedLessons.forEach((lesson) => {
              const dateKey = lesson.date.toDateString();
              if (!lessonsByDay.has(dateKey)) {
                lessonsByDay.set(dateKey, []);
              }
              lessonsByDay.get(dateKey)!.push(lesson);
            });

            lessonsByDay.forEach((dailyLessons) => {
              for (let i = 1; i < dailyLessons.length; i++) {
                if (dailyLessons[i].subject !== dailyLessons[i - 1].subject) {
                  subjectChanges++;
                }
              }
            });

            // Property: Number of subject changes should be reasonable
            const totalLessons = lessons.length;
            const changeRatio = subjectChanges / Math.max(totalLessons - 1, 1);

            // Should not switch subjects more than 70% of the time
            return changeRatio <= 0.7;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The schedule optimization minimizes context switching by ensuring the ratio of subject changes does not exceed 70% within daily lesson plans.


it('should maintain valid elementary grade ranges', () => {
      fc.assert(
        fc.property(domainArbitraries.grade, (grade) => {
          // Property: All grades should be within elementary range (1-8)
          return grade >= 1 && grade <= 8;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Grades should always be within the elementary range of 1 to 8.


test('onChange callback has called on set new value', () => {
  fc.assert(
    fc.property(recordWithNewValueArbitrary, ([record, value]) => {
      const onChangeSpy = jest.fn()
      const { result } = renderHook(() => useRecordRoot(TestContext, record, onChangeSpy))
      const updater = result.current[1].value[1]

      Object.keys(record).forEach((key) => {
        updater(key, jest.fn().mockReturnValue(value))
      })

      expect(onChangeSpy.mock.calls.length).toBe(Object.keys(record).length)
    })
  )
})

Summary: The `onChange` callback should be called once for each key when a new value is set in the record.


it('should ensure grade progression ordering', () => {
      fc.assert(
        fc.property(fc.array(domainArbitraries.grade, { minLength: 3, maxLength: 8 }), (grades) => {
          // Property: Grades should follow natural ordering
          const sortedGrades = [...grades].sort((a, b) => a - b);

          for (let i = 1; i < sortedGrades.length; i++) {
            if (sortedGrades[i] < sortedGrades[i - 1]) {
              return false;
            }
          }

          return true;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Grades in an array should follow natural ascending order after sorting.


test('Retrieve correct value from context by key', () => {
  fc.assert(
    fc.property(keyArbitrary, fc.anything(), (key, value) => {
      const getterSpy = jest.fn().mockReturnValue(value)
      const { result } = renderHook(() => useLeaf(TestContext, key), {
        wrapper: ({ children }) => createElement(TestContext.Provider, { value: [getterSpy, jest.fn()] }, children),
      })

      expect(result.current[0]).toBe(value)
      expect(getterSpy.mock.calls[0]).toEqual([key])
    })
  )
})

Summary: `useLeaf` retrieves the correct value from the context using the given key.


it('should maintain appropriate complexity for grade levels', () => {
      fc.assert(
        fc.property(domainArbitraries.curriculumProgression, (progression) => {
          // Property: Curriculum complexity should increase with grade level
          const { grade, complexity } = progression;

          switch (complexity) {
            case 'basic':
              return grade >= 1 && grade <= 3;
            case 'intermediate':
              return grade >= 4 && grade <= 6;
            case 'advanced':
              return grade >= 7 && grade <= 8;
            default:
              return false;
          }
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Curriculum complexity should appropriately align with grade levels, ensuring basic complexity for grades 1-3, intermediate for grades 4-6, and advanced for grades 7-8.


it('should ensure prerequisite knowledge progression', () => {
      fc.assert(
        fc.property(
          fc.tuple(domainArbitraries.grade, domainArbitraries.grade),
          ([lowerGrade, higherGrade]) => {
            // Property: Higher grades should build on lower grade concepts
            if (lowerGrade >= higherGrade) {
              return true; // Skip if not progressive
            }

            // Mock function to get complexity for a grade
            const getComplexityLevel = (grade: number): number => {
              if (grade <= 3) return 1; // Basic
              if (grade <= 6) return 2; // Intermediate
              return 3; // Advanced
            };

            const lowerComplexity = getComplexityLevel(lowerGrade);
            const higherComplexity = getComplexityLevel(higherGrade);

            return higherComplexity >= lowerComplexity;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Higher grade complexity should be equal to or greater than lower grade complexity for proper knowledge progression.


it('should match lesson duration to grade attention spans', () => {
      fc.assert(
        fc.property(
          domainArbitraries.grade,
          domainArbitraries.lessonDuration,
          (grade, duration) => {
            // Property: Lesson duration should match developmental attention spans
            const getMaxAttentionSpan = (gradeLevel: number): number => {
              // Rule of thumb: Grade level × 5-10 minutes
              if (gradeLevel <= 2) return 20; // 15-20 minutes max
              if (gradeLevel <= 4) return 40; // 30-40 minutes max
              if (gradeLevel <= 6) return 60; // 45-60 minutes max
              return 90; // Up to 90 minutes for older students
            };

            const maxDuration = getMaxAttentionSpan(grade);
            return duration <= maxDuration;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Lesson durations should not exceed the maximum attention span associated with a given grade level.


it('should ensure age-appropriate vocabulary complexity', () => {
      fc.assert(
        fc.property(domainArbitraries.fullCurriculumExpectation, (expectation) => {
          // Property: Vocabulary should be appropriate for grade level
          const { grade, description } = expectation;
          const words = description.toLowerCase().split(/\s+/);

          // Count complex words (more than 7 characters as a simple heuristic)
          const complexWords = words.filter((word) => word.length > 7);
          const complexityRatio = complexWords.length / words.length;

          if (grade <= 3) {
            return complexityRatio <= 0.2; // Max 20% complex words
          } else if (grade <= 6) {
            return complexityRatio <= 0.4; // Max 40% complex words
          } else {
            return complexityRatio <= 0.6; // Max 60% complex words
          }
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Vocabulary complexity in curriculum descriptions should be appropriate for the specified grade level, limiting the ratio of complex words based on grade.


test('Updater from context throw error if key not exists in data', () => {
  fc.assert(
    fc.property(arrayWithInvalidKeyArbitrary, ([array, invalidKey]) => {
      const onChangeSpy = jest.fn().mockImplementation((cb: (prev: unknown[]) => void) => cb(array))
      const { result } = renderHook(() => useArrayRoot(TestContext, array, onChangeSpy, getKeyIndex))
      const updater = result.current[1].value[1]

      expect(() => updater(invalidKey, () => undefined)).toThrow(RangeError)
    })
  )
})

Summary: An error is thrown by an updater function when a non-existent key is provided in the data.


it('should ensure appropriate cognitive load distribution', () => {
      fc.assert(
        fc.property(
          domainArbitraries.grade,
          fc.array(domainArbitraries.activityType, { minLength: 1, maxLength: 5 }),
          (grade, activities) => {
            // Property: Cognitive load should be appropriate for grade level
            const cognitiveWeights = new Map([
              ['discussion', 2],
              ['hands-on', 1],
              ['investigation', 4],
              ['presentation', 3],
              ['game', 1],
              ['experiment', 4],
              ['reading', 2],
              ['writing', 3],
              ['problem-solving', 4],
              ['collaboration', 2],
            ]);

            const totalCognitiveLoad = activities.reduce(
              (sum, activity) => sum + (cognitiveWeights.get(activity) || 2),
              0,
            );

            const averageLoad = totalCognitiveLoad / activities.length;

            if (grade <= 3) {
              return averageLoad <= 2.5; // Lower cognitive load
            } else if (grade <= 6) {
              return averageLoad <= 3.5; // Medium cognitive load
            } else {
              return averageLoad <= 4.0; // Higher cognitive load allowed
            }
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The average cognitive load of activities should be appropriate for the specified grade level, with lower grades having lower allowable load.


test("SShort fuzzing", () => {
    fc.assert(
      fc.property(fc.integer({ min: MIN_I16, max: MAX_I16 }), (val) => {
        const serialized = SShort(val).toHex();
        expect(serialized).to.be.equal(Value$.ofShort(val).toHex()); // ensure compatibility with sigmastate-js
        expect(SConstant.from(serialized).data).to.be.equal(val);
      })
    );
  })

Summary: The test ensures that a 16-bit integer, when processed through `SShort`, produces a serialized hex representation compatible with `Value$.ofShort`, and that `SConstant.from` can accurately deserialize it back to the original integer.


it('should maintain mathematics concept progression', () => {
      fc.assert(
        fc.property(
          domainArbitraries.grade,
          domainArbitraries.curriculumStrand,
          (grade, strand) => {
            // Property: Mathematics concepts should follow developmental sequence
            const mathProgressionMap = new Map([
              [1, ['Number Sense']],
              [2, ['Number Sense', 'Measurement']],
              [3, ['Number Sense', 'Measurement', 'Geometry']],
              [4, ['Number Sense', 'Measurement', 'Geometry', 'Data Management']],
              [5, ['Number Sense', 'Measurement', 'Geometry', 'Data Management']],
              [6, ['Number Sense', 'Algebra', 'Measurement', 'Geometry', 'Data Management']],
              [7, ['Number Sense', 'Algebra', 'Measurement', 'Geometry', 'Data Management']],
              [8, ['Number Sense', 'Algebra', 'Measurement', 'Geometry', 'Data Management']],
            ]);

            const mathStrands = [
              'Number Sense',
              'Algebra',
              'Geometry',
              'Measurement',
              'Data Management',
            ];

            if (!mathStrands.includes(strand)) {
              return true; // Not a math strand, skip validation
            }

            const gradeStrands = mathProgressionMap.get(grade) || [];
            return gradeStrands.includes(strand);
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Mathematics concepts should be presented in a developmental sequence appropriate for each grade level, ensuring that each strand is associated with the correct grade.


it('should distribute assessment types appropriately by grade', () => {
      fc.assert(
        fc.property(
          domainArbitraries.grade,
          domainArbitraries.assessmentDistribution,
          (grade, distribution) => {
            // Property: Assessment distribution should match developmental needs
            const { diagnostic, formative, summative, total } = distribution;

            const formativeRatio = formative / total;
            const summativeRatio = summative / total;

            if (grade <= 3) {
              // Lower grades: More formative, less summative
              return formativeRatio >= 0.6 && summativeRatio <= 0.3;
            } else if (grade <= 6) {
              // Middle grades: Balanced approach
              return formativeRatio >= 0.5 && summativeRatio <= 0.4;
            } else {
              // Upper grades: More summative assessment preparation
              return formativeRatio >= 0.4 && summativeRatio <= 0.5;
            }
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Distribution of assessment types must align with developmental needs by grade level: lower grades emphasize formative, middle grades are balanced, and upper grades focus more on summative assessments.


test("Round-trip fuzzing", () => {
    fc.assert(
      fc.property(fc.integer({ min: MIN_I32, max: MAX_I32 }), (n) => {
        expect(zigZag32.decode(zigZag32.encode(n))).to.be.equal(n);
      })
    );
  })

Summary: Encoding and then decoding an integer using `zigZag32` should return the original integer.


it('should ensure appropriate assessment frequency', () => {
      fc.assert(
        fc.property(
          domainArbitraries.grade,
          fc.integer({ min: 1, max: 20 }), // weeks in a term
          (grade, weeksInTerm) => {
            // Property: Assessment frequency should match grade level needs
            const getMinFormativeAssessments = (gradeLevel: number, weeks: number): number => {
              if (gradeLevel <= 3) return weeks * 2; // 2 per week minimum
              if (gradeLevel <= 6) return Math.floor(weeks * 1.5); // 1.5 per week
              return weeks; // 1 per week minimum
            };

            const getMaxSummativeAssessments = (gradeLevel: number, weeks: number): number => {
              if (gradeLevel <= 3) return Math.ceil(weeks / 4); // 1 per 4 weeks max
              if (gradeLevel <= 6) return Math.ceil(weeks / 3); // 1 per 3 weeks max
              return Math.ceil(weeks / 2); // 1 per 2 weeks max
            };

            const minFormative = getMinFormativeAssessments(grade, weeksInTerm);
            const maxSummative = getMaxSummativeAssessments(grade, weeksInTerm);

            // Properties should be within reasonable bounds
            return minFormative > 0 && maxSummative > 0 && minFormative >= maxSummative;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: The property ensures that the minimum number of formative assessments and the maximum number of summative assessments per term align with the defined needs based on grade level, with the constraint that formative assessments are more frequent than summative assessments.


it('should introduce learning skills age-appropriately', () => {
      fc.assert(
        fc.property(domainArbitraries.grade, domainArbitraries.learningSkill, (grade, skill) => {
          // Property: Learning skills should be introduced when developmentally appropriate
          const skillIntroductionGrades = new Map([
            ['responsibility', 1],
            ['organization', 2],
            ['independent work', 3],
            ['collaboration', 1],
            ['initiative', 4],
            ['self-regulation', 5],
          ]);

          const introductionGrade = skillIntroductionGrades.get(skill) || 1;
          return grade >= introductionGrade;
        }),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Learning skills should be introduced at an age-appropriate grade level, according to predefined criteria.