Brazilian CPF

class CPF {
  private value: string;
 
  constructor(cpf: string) {
    if (!this.validateCPF(cpf)) {
      throw new Error("Invalid CPF. Please provide a valid CPF number.");
    }
    this.value = cpf;
  }
 
  equals(other: CPF): boolean {
    return this.value === other.value;
  }
 
  toString(): string {
    return this.value;
  }
 
  private validateCPF(cpf: string): boolean {
    // Remove non-numeric characters and check if the length is valid
    cpf = cpf.replace(/\D/g, "");
    if (cpf.length !== 11) {
      return false;
    }
    // Check for known invalid CPFs
    const invalidCPFs = [
      "00000000000",
      "11111111111",
      "22222222222",
      "33333333333",
      "44444444444",
      "55555555555",
      "66666666666",
      "77777777777",
      "88888888888",
      "99999999999",
    ];
    if (invalidCPFs.includes(cpf)) {
      return false;
    }
    // Calculate and verify the CPF checksum
    const numbers = cpf.substring(0, 9).split("").map(Number);
    const checksum1 =
      numbers.reduce((sum, value, index) => sum + value * (10 - index), 0) % 11;
    const checksum2 =
      numbers.reduce((sum, value, index) => sum + value * (11 - index), 0) % 11;
    const validChecksum1 = checksum1 < 2 ? 0 : 11 - checksum1;
    const validChecksum2 = checksum2 < 2 ? 0 : 11 - checksum2;
    return numbers[9] === validChecksum1 && numbers[10] === validChecksum2;
  }
}
 
// Example usage:
const validCPF = new CPF("123.456.789-09"); // A valid CPF
const invalidCPF = new CPF("123.456.789-00"); // An invalid CPF
console.log(validCPF.toString()); // Output: "12345678909"
console.log(invalidCPF.toString()); // Throws an error for an invalid CPF

Specs

import { CPF } from "./cpf"; // Import the CPF class
 
describe("CPF", () => {
  describe("constructor", () => {
    it("should create a CPF instance with a valid CPF number", () => {
      const cpf = new CPF("123.456.789-09");
      expect(cpf).toBeDefined();
    });
 
    it("should throw an error for an invalid CPF number", () => {
      expect(() => new CPF("123.456.789-00")).toThrow();
      expect(() => new CPF("invalid_cpf")).toThrow();
    });
  });
 
  describe("equals", () => {
    it("should return true when comparing two CPF instances with the same CPF number", () => {
      const cpf1 = new CPF("123.456.789-09");
      const cpf2 = new CPF("12345678909");
      expect(cpf1.equals(cpf2)).toBe(true);
    });
 
    it("should return false when comparing two CPF instances with different CPF numbers", () => {
      const cpf1 = new CPF("123.456.789-09");
      const cpf2 = new CPF("987.654.321-09");
      expect(cpf1.equals(cpf2)).toBe(false);
    });
  });
 
  describe("toString", () => {
    it("should return the string representation of the CPF", () => {
      const cpf = new CPF("123.456.789-09");
      expect(cpf.toString()).toBe("12345678909");
    });
  });
});