Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(domain): ドメインモデルのバリデーションとテストの実装 #174

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/domain/post.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, expect, it } from "vitest";
import { Post, PostArgs } from "./post.js";
import { Snowflake } from "../helpers/id_generator.js";
import { Media } from "./media.js";

describe("Post", () => {
const defaultPostArgs: PostArgs = {
id: "10101450391945216" as Snowflake,
authorID: "10101451896913920" as Snowflake,
text: "Hello, world!",
visibility: 0,
createdAt: new Date(),
attachments: [],
reactions: [],
};

it("添付ファイルは16個以上添付できない", () => {
expect(() => {
new Post({
...defaultPostArgs,
attachments: new Array(17).fill({} as Media),
});
}).toThrowError(
new Error(
"failed to create post: The number of attachments must be less than 16.",
),
);
});

it("ファイルを添付できる", () => {
expect(() => {
new Post({
...defaultPostArgs,
attachments: new Array(10).fill({} as Media),
});
}).toBeTruthy();
});
});
19 changes: 19 additions & 0 deletions src/domain/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ import { Snowflake } from "../helpers/id_generator.js";
import { User } from "./user.js";
import { Media } from "./media.js";

export interface PostArgs {
id: Snowflake;
authorID: Snowflake;
text: string;
visibility: number;
createdAt: Date;
attachments: Array<Media>;
reactions: Array<PostReactionEvent>;
}

export class Post {
get visibility(): number {
return this._visibility;
Expand Down Expand Up @@ -54,6 +64,7 @@ export class Post {
attachments: Array<Media>;
reactions: Array<PostReactionEvent>;
}) {
this.validate(args);
this._id = args.id;
this._authorID = args.authorID;

Expand All @@ -70,6 +81,14 @@ export class Post {
}
return text;
}

private validate(args: PostArgs) {
if (args.attachments.length > 16) {
throw new Error(
"failed to create post: The number of attachments must be less than 16.",
);
}
}
}

export class PostReactionEvent {
Expand Down
116 changes: 116 additions & 0 deletions src/domain/server.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { describe, expect, it } from "vitest";
import { Server, ServerArgs } from "./server.js";
import { Snowflake } from "../helpers/id_generator.js";

describe("Server", () => {
const defaultServerArgs: ServerArgs = {
id: "10101294855225344" as Snowflake,
host: "social.example.jp",
softwareName: "Mastodon",
softwareVersion: "4.0.0",
name: "example social",
description: "this is example social",
maintainer: "example maintainer",
maintainerEmail: "[email protected]",
iconURL: "https://social.example.jp/icon.png",
faviconURL: "https://social.example.jp/favicon.png",
};

it("128文字以上のホスト名は設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
host: "a".repeat(128 + 1),
});
}).toThrowError(new Error("failed to create server: host is too long"));
});

it("4文字以下のホスト名は設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
host: "a.b",
});
}).toThrowError(new Error("failed to create server: host is too short"));
});

it("ホスト名を設定できる", () => {
expect(() => {
new Server({
...defaultServerArgs,
});
}).toBeTruthy();
});

it("128文字以上のソフトウェア名は設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
softwareName: "a".repeat(128 + 1),
});
}).toThrowError(
new Error("failed to create server: softwareName is too long"),
);
});

it("ソフトウェア名を設定できる", () => {
expect(() => {
new Server({
...defaultServerArgs,
});
}).toBeTruthy();
});

it("128文字以上のソフトウェアバージョンは設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
softwareVersion: "a".repeat(128 + 1),
});
}).toThrowError(
new Error("failed to create server: softwareVersion is too long"),
);
});

it("128文字以上のサーバー名は設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
name: "a".repeat(128 + 1),
});
}).toThrowError(new Error("failed to create server: name is too long"));
});

it("3000文字以上のサーバー説明文は設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
description: "a".repeat(3000 + 1),
});
}).toThrowError(
new Error("failed to create server: description is too long"),
);
});

it("256文字以上の管理者名は設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
maintainer: "a".repeat(256 + 1),
});
}).toThrowError(
new Error("failed to create server: maintainer is too long"),
);
});

it("256文字以上の管理者メールアドレスは設定できない", () => {
expect(() => {
new Server({
...defaultServerArgs,
maintainerEmail: "a".repeat(256 + 1),
});
}).toThrowError(
new Error("failed to create server: maintainerEmail is too long"),
);
});
});
47 changes: 47 additions & 0 deletions src/domain/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import { Snowflake } from "../helpers/id_generator.js";

export interface ServerArgs {
id: Snowflake;
host: string;
softwareName: string;
softwareVersion: string;
name: string;
description: string;
maintainer: string;
maintainerEmail: string;
iconURL: string;
faviconURL: string;
}

export class Server {
get softwareName(): string {
return this._softwareName;
Expand Down Expand Up @@ -105,6 +118,8 @@ export class Server {
iconURL: string;
faviconURL: string;
}) {
this.validate(args);

this._id = args.id;
this._host = args.host;
this._softwareName = args.softwareName;
Expand All @@ -116,4 +131,36 @@ export class Server {
this._iconURL = args.iconURL;
this._faviconURL = args.faviconURL;
}

private validate(args: ServerArgs) {
if ([...args.host].length > 128) {
throw new Error("failed to create server: host is too long");
} else if ([...args.host].length < 4) {
throw new Error("failed to create server: host is too short");
}

if ([...args.softwareName].length > 128) {
throw new Error("failed to create server: softwareName is too long");
}

if ([...args.softwareVersion].length > 128) {
throw new Error("failed to create server: softwareVersion is too long");
}

if ([...args.name].length > 128) {
throw new Error("failed to create server: name is too long");
}

if ([...args.description].length > 3000) {
throw new Error("failed to create server: description is too long");
}

if ([...args.maintainer].length > 256) {
throw new Error("failed to create server: maintainer is too long");
}

if ([...args.maintainerEmail].length > 256) {
throw new Error("failed to create server: maintainerEmail is too long");
}
}
}
101 changes: 101 additions & 0 deletions src/domain/user.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { describe, expect, it } from "vitest";
import { User, UserAPData } from "./user.js";
import { Snowflake } from "../helpers/id_generator.js";

describe("User domain model", () => {
const defaultDataArgs = {
id: "10100912877076480" as Snowflake,
serverID: "10100914303139840" as Snowflake,
handle: "test",
fullHandle: "[email protected]",
nickName: "TestUser",
bio: "testのユーザーです",
headerImageURL: "https://image.example.jp/header.png",
iconImageURL: "https://image.example.jp/icon.png",
password: "efnrkgnjkneiug",
role: 0,
createdAt: new Date(),
isLocalUser: true,
following: [],
apData: new UserAPData({
followersURL: "https://example.jp/followers",
followingURL: "https://example.jp/following",
inboxURL: "https://example.jp/inbox",
outboxURL: "https://example.jp/outbox",
privateKey: "",
publicKey: "",
userAPID: "10100938952278016",
userID: "10100912877076480" as Snowflake,
}),
};

it("64文字以内の表示名は設定できる", () => {
const u = new User({ ...defaultDataArgs, nickName: "テストユーザー" });
expect(u).toBeTruthy();
});

it("64文字以上の表示名は設定できない", () => {
expect(
() =>
new User({
...defaultDataArgs,
nickName: "テストユーザー".repeat(10),
}),
).toThrowError(new Error("failed to create user: nickname is too long"));
});

it("64文字以上のハンドルは設定できない", () => {
expect(
() =>
new User({
...defaultDataArgs,
handle: "test_user".repeat(20),
}),
).toThrowError(new Error("failed to create user: handle is too long"));
});

it("64文字以下のハンドルを設定できる", () => {
expect(new User({ ...defaultDataArgs, handle: "test_user" })).toBeTruthy();
});

it("空文字列は設定できない", () => {
expect(() => new User({ ...defaultDataArgs, handle: "" })).toThrowError(
new Error("failed to create user: handle is too short"),
);
});

it("フルハンドルを設定できる", () => {
expect(
new User({ ...defaultDataArgs, fullHandle: "[email protected]" }),
).toBeTruthy();
});

it("FQDNとして成立しない長さのフルハンドルは設定できない", () => {
expect(
() =>
new User({
...defaultDataArgs,
fullHandle: "[email protected]",
}),
).toThrowError(new Error("failed to create user: fullHandle is too short"));
});

it("3000文字以上のbioは設定できない", () => {
expect(
() =>
new User({
...defaultDataArgs,
bio: "a".repeat(3001),
}),
).toThrowError(new Error("failed to create user: bio is too long"));
});

it("bioを設定できる", () => {
expect(
new User({
...defaultDataArgs,
bio: "テストユーザーです",
}),
).toBeTruthy();
});
});
Loading