File size: 3,976 Bytes
3201ca6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { describe, expect, it } from "vitest";
import {
  validateFiles,
  validateIndividualFileSizes,
  validateTotalFileSize,
} from "#/utils/file-validation";

const MEBIBYTE = 1024 * 1024;
const THREE_MEBIBYTES = 3 * MEBIBYTE;

function fileWithSize(name: string, size: number): File {
  const file = new File([], name);
  Object.defineProperty(file, "size", { value: size });
  return file;
}

describe("attachment size validation", () => {
  it("accepts a file at the 3 MiB boundary and rejects one byte over it", () => {
    expect(
      validateIndividualFileSizes([
        fileWithSize("at-limit.zip", THREE_MEBIBYTES),
      ]),
    ).toEqual({ isValid: true });

    expect(
      validateIndividualFileSizes([
        fileWithSize("over-limit.zip", THREE_MEBIBYTES + 1),
      ]),
    ).toEqual({
      isValid: false,
      errorMessage: "Files exceeding 3MB are not allowed: over-limit.zip",
      oversizedFiles: ["over-limit.zip"],
    });
  });

  it("reports every oversized file by name in selection order", () => {
    const result = validateIndividualFileSizes([
      fileWithSize("first.bin", THREE_MEBIBYTES + 1),
      fileWithSize("allowed.bin", THREE_MEBIBYTES),
      fileWithSize("second.bin", 4 * MEBIBYTE),
    ]);

    expect(result).toEqual({
      isValid: false,
      errorMessage:
        "Files exceeding 3MB are not allowed: first.bin, second.bin",
      oversizedFiles: ["first.bin", "second.bin"],
    });
  });

  it("accepts new and existing files whose combined size is exactly 3 MiB", () => {
    expect(
      validateTotalFileSize(
        [fileWithSize("new.bin", MEBIBYTE)],
        [fileWithSize("existing.bin", 2 * MEBIBYTE)],
      ),
    ).toEqual({ isValid: true });
  });

  it("rejects a new and existing aggregate one byte over the limit", () => {
    expect(
      validateTotalFileSize(
        [fileWithSize("new.bin", MEBIBYTE + 1)],
        [fileWithSize("existing.bin", 2 * MEBIBYTE)],
      ),
    ).toEqual({
      isValid: false,
      errorMessage:
        "Total file size would be 3.0MB, exceeding the 3MB limit. Please select fewer or smaller files.",
    });
  });

  it("formats an oversized aggregate to one decimal place", () => {
    expect(
      validateTotalFileSize(
        [fileWithSize("new.bin", 2 * MEBIBYTE)],
        [fileWithSize("existing.bin", 1.25 * MEBIBYTE)],
      ),
    ).toEqual({
      isValid: false,
      errorMessage:
        "Total file size would be 3.3MB, exceeding the 3MB limit. Please select fewer or smaller files.",
    });
  });

  it("uses an empty existing-file list when none is provided", () => {
    expect(
      validateTotalFileSize([
        fileWithSize("new.bin", THREE_MEBIBYTES + MEBIBYTE),
      ]),
    ).toEqual({
      isValid: false,
      errorMessage:
        "Total file size would be 4.0MB, exceeding the 3MB limit. Please select fewer or smaller files.",
    });
  });

  it("returns the individual-file error before the aggregate-size error", () => {
    expect(
      validateFiles(
        [fileWithSize("too-large.bin", THREE_MEBIBYTES + 1)],
        [fileWithSize("existing.bin", MEBIBYTE)],
      ),
    ).toEqual({
      isValid: false,
      errorMessage: "Files exceeding 3MB are not allowed: too-large.bin",
      oversizedFiles: ["too-large.bin"],
    });
  });

  it("checks the aggregate after every new file passes individually", () => {
    expect(
      validateFiles([
        fileWithSize("first.bin", 2 * MEBIBYTE),
        fileWithSize("second.bin", 2 * MEBIBYTE),
      ]),
    ).toEqual({
      isValid: false,
      errorMessage:
        "Total file size would be 4.0MB, exceeding the 3MB limit. Please select fewer or smaller files.",
    });
  });

  it("accepts an aggregate at the limit through the combined validator", () => {
    expect(
      validateFiles(
        [fileWithSize("new.bin", MEBIBYTE)],
        [fileWithSize("existing.bin", 2 * MEBIBYTE)],
      ),
    ).toEqual({ isValid: true });
  });
});