Skip to content

Commit

Permalink
adds dna rna conversion endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverslade committed Mar 21, 2024
1 parent b039513 commit e6bfa52
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 128 deletions.
15 changes: 0 additions & 15 deletions src/controllers/product-controller.ts

This file was deleted.

25 changes: 25 additions & 0 deletions src/controllers/rna-controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Request, Response } from "express";
import { toRna } from "../services/rna-service";
import { InvalidDnaError } from "../models/errors/InvalidDnaError";

export const convertDnaToRnaString = async (req: Request, res: Response) => {
try {
const dna = req.body.dna;
const result = toRna(dna as string);
res.json(result);
} catch (error) {
if (error instanceof InvalidDnaError) {
res.status(400).json({ message: "Bad request: " + error.message });
} else {
res.status(500).json({
message:
"Internal server error: " + (error as Error).message ||
"Unknown error.",
});
}
}
};

export const health = (req: Request, res: Response) => {
res.send("OK");
};
10 changes: 0 additions & 10 deletions src/database.ts

This file was deleted.

6 changes: 4 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import express from "express";
import { health, getAllProducts } from "./controllers/product-controller";
import { health, convertDnaToRnaString } from "./controllers/rna-controller";

const app = express();
const PORT = 3000;

app.use(express.json());

app.get("/health", health);
app.get("/products", getAllProducts);
app.post("/convert-dna-to-rna", convertDnaToRnaString);

app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
Expand Down
6 changes: 6 additions & 0 deletions src/models/errors/InvalidDnaError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export class InvalidDnaError extends Error {
constructor(message?: string) {
super(message);
this.name = "InvalidDnaError";
}
}
38 changes: 0 additions & 38 deletions src/models/product.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/services/product-service.ts

This file was deleted.

16 changes: 16 additions & 0 deletions src/services/rna-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { InvalidDnaError } from '../models/errors/InvalidDnaError';

export function toRna(sequence: string): string {
if (!sequence.match(/^[GCTA]+$/))
throw new InvalidDnaError("Invalid input DNA.");
const dnaToRnaMap: Record<string, string> = {
G: "C",
C: "G",
T: "A",
A: "U",
};
return sequence
.split("")
.map((letter) => dnaToRnaMap[letter])
.join("");
}
58 changes: 0 additions & 58 deletions test/unit/controllers/product-controller.test.ts

This file was deleted.

94 changes: 94 additions & 0 deletions test/unit/controllers/rna-controller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Request, Response } from "express";
import {
convertDnaToRnaString,
health,
} from "../../../src/controllers/rna-controller";
import { toRna } from "../../../src/services/rna-service";
import { InvalidDnaError } from "../../../src/models/errors/InvalidDnaError";

jest.mock("../../../src/services/rna-service");

describe("rna-controller", () => {
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let mockJson: jest.Mock;
let mockStatus: jest.Mock;

beforeEach(() => {
mockJson = jest.fn();
mockStatus = jest.fn().mockReturnValue({ json: mockJson });
mockRequest = {};
mockResponse = {
json: mockJson,
status: mockStatus,
};
});

afterEach(() => {
jest.clearAllMocks();
});

it("convertDnaToRnaString should return RNA string", async () => {
const mockDna = "GCTA";
const mockRna = "CGAU";
(toRna as jest.Mock).mockReturnValue(mockRna);
mockRequest.body = { dna: mockDna };

await convertDnaToRnaString(
mockRequest as Request,
mockResponse as Response
);

expect(toRna).toHaveBeenCalledWith(mockDna);
expect(mockJson).toHaveBeenCalledWith(mockRna);
});

it("convertDnaToRnaString should handle invalid DNA input", async () => {
const mockDna = "GCTAX";
const mockError = new InvalidDnaError("Invalid input DNA.");
(toRna as jest.Mock).mockImplementation(() => {
throw mockError;
});
mockRequest.body = { dna: mockDna };

await convertDnaToRnaString(
mockRequest as Request,
mockResponse as Response
);

expect(toRna).toHaveBeenCalledWith(mockDna);
expect(mockStatus).toHaveBeenCalledWith(400);
expect(mockJson).toHaveBeenCalledWith({
message: "Bad request: " + mockError.message,
});
});

it("convertDnaToRnaString should handle internal server error", async () => {
const mockDna = "GCTA";
const mockError = new Error("Unexpected error.");
(toRna as jest.Mock).mockImplementation(() => {
throw mockError;
});
mockRequest.body = { dna: mockDna };

await convertDnaToRnaString(
mockRequest as Request,
mockResponse as Response
);

expect(toRna).toHaveBeenCalledWith(mockDna);
expect(mockStatus).toHaveBeenCalledWith(500);
expect(mockJson).toHaveBeenCalledWith({
message: "Internal server error: " + mockError.message,
});
});

it("health should return OK", () => {
const mockSend = jest.fn();
mockResponse.send = mockSend;

health(mockRequest as Request, mockResponse as Response);

expect(mockSend).toHaveBeenCalledWith("OK");
});
});
35 changes: 35 additions & 0 deletions test/unit/services/rna-serivce.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { toRna } from "../../../src/services/rna-service";

describe("Transcriptor", () => {
it("transcribes cytosine to guanine", () => {
expect(toRna("C")).toEqual("G");
});

it("transcribes guanine to cytosine", () => {
expect(toRna("G")).toEqual("C");
});

it("transcribes adenine to uracil", () => {
expect(toRna("A")).toEqual("U");
});

it("transcribes thymine to adenine", () => {
expect(toRna("T")).toEqual("A");
});

it("transcribes all dna nucleotides to their rna complements", () => {
expect(toRna("ACGTGGTCTTAA")).toEqual("UGCACCAGAAUU");
});

it("correctly handles invalid input", () => {
expect(() => toRna("U")).toThrowError("Invalid input DNA.");
});

it("correctly handles completely invalid input", () => {
expect(() => toRna("XXX")).toThrowError("Invalid input DNA.");
});

it("correctly handles partially invalid input", () => {
expect(() => toRna("ACGTXXXCTTAA")).toThrowError("Invalid input DNA.");
});
});

0 comments on commit e6bfa52

Please sign in to comment.