Skip to content

Commit

Permalink
Add validation for customer paints being out of the range.
Browse files Browse the repository at this point in the history
  • Loading branch information
ihsw committed Mar 7, 2018
1 parent b342725 commit 278cad9
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
30 changes: 28 additions & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export enum ParseErrorCode {
MissingCustomers,
InvalidColorCount,
InvalidPaintFormat,
InvalidColor
InvalidColor,
CustomerPaintOutOfRange
}

export class ParseError extends Error {
Expand All @@ -17,6 +18,10 @@ export class ParseError extends Error {

type Type = "M" | " G";

interface Color {
type: Type;
}

interface Paint {
type: Type;
color: number;
Expand All @@ -29,20 +34,24 @@ export interface Customer {
export class Order {
colorCount: number;
customers: Customer[];
colors: Color[];

constructor(colorCount: number, customers: Customer[]) {
this.colorCount = colorCount;
this.customers = customers;
this.colors = [];
}
}

export const parse = (input: string): Order => {
input = input.trim();

// validating input
if (input.length === 0) {
throw new ParseError("Blank input!", ParseErrorCode.BlankInput);
}

// stripping comments and trimming whitespace
const results = input.split("\n").map((result) => {
if (result.indexOf("#") === -1) {
return result;
Expand All @@ -51,26 +60,33 @@ export const parse = (input: string): Order => {
return result.split("#")[0];
}).map((result) => result.trim());

// validating the color count
const colorCount = Number(results[0]);
if (isNaN(colorCount)) {
throw new ParseError("First line was NaN!", ParseErrorCode.InvalidColorCount);
}

// validating the list of customers
if (results.length === 1) {
throw new ParseError("A paint color count was provided but no customers!", ParseErrorCode.MissingCustomers);
}

// resolving customers
const customers = results.slice(1).map((result, resultIndex) => {
// validating the list of paints
const paintResults = result.split(" ");
if (paintResults.length % 2 > 0) {
throw new ParseError("Invalid paint format!", ParseErrorCode.InvalidPaintFormat);
}

// resolving paints
const paints: Paint[] = Array.from((new Array(paintResults.length / 2)).keys()).map((i) => {
const currentIndex = i * 2;

// validating the color choice
const color = Number(paintResults[currentIndex]);
if (isNaN(color)) {
throw new ParseError(`Color at line ${resultIndex + 1} is invalid!`, ParseErrorCode.InvalidColor);
throw new ParseError(`Color at line ${resultIndex + 1} is NaN!`, ParseErrorCode.InvalidColor);
}

return <Paint>{
Expand All @@ -84,5 +100,15 @@ export const parse = (input: string): Order => {
};
});

// validating each customer's paint
const invalidCustomers = customers.filter((customer) => {
return customer.paints.filter(
(paint) => !(paint.color > 0 && paint.color <= colorCount)
).length > 0;
});
if (invalidCustomers.length > 0) {
throw new ParseError(`Order has ${invalidCustomers.length} customers with invalid paint colors!`, ParseErrorCode.CustomerPaintOutOfRange);
}

return new Order(colorCount, customers);
};
8 changes: 8 additions & 0 deletions src/test/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,12 @@ describe("Parser", () => {
{paints: [{color: 5, type: "M"}]}
]);
});

it("Should fail on paint out of range", () => {
const paintOutOfRangeExample = fs.readFileSync("./test-fixtures/example-7-paint-out-of-range").toString();
assert.throws(
() => parse(paintOutOfRangeExample),
(err: ParseError) => err instanceof ParseError && err.code === ParseErrorCode.CustomerPaintOutOfRange
);
});
});
2 changes: 2 additions & 0 deletions test-fixtures/example-7-paint-out-of-range
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1
2 M

0 comments on commit 278cad9

Please sign in to comment.