## DEV Community is a community of 846,223 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Nicolas DUBIEN

Posted on

# Advent of PBT 2021 - Day 24 - Solution

Our algorithm was: christmasFactorySchedule.
Go to the subject itself for more details

CodeSandbox with a possible set of properties you may have come with: https://codesandbox.io/s/advent-of-pbt-day-24-solution-68w81?file=/src/index.spec.ts&previewwindow=tests

Today, we will just generate the inputs requested by the algorithm. Actually there is something cool regarding this algorithm: computing the result is complex, but checking it is simple.

So we will just generate tasks being dependent from each others without cycles and ask the scheduler what's the best option for us. Then we just have to confirm the schedule is following our constraints.

But in order to generate our tasks we need to be careful as generating cycles could be easy (and trying to detect them would add some unwanted complexity in the tests).

Here is the implementation I came with for `tasksArbitrary`:

``````function tasksArbitrary(): fc.Arbitrary<Task[]> {
return fc
.tuple(
tasksLayerArbitrary(0), // tasks with ids in 0 to 9, without any dependencies
tasksLayerArbitrary(1), // tasks with ids in 10 to 19, with possible dependencies onto 0 to 9
tasksLayerArbitrary(2), // tasks with ids in 20 to 29, with possible dependencies onto 0 to 19
tasksLayerArbitrary(3) // tasks with ids in 30 to 39, with possible dependencies onto 0 to 29
)
// Merge all the layers together
// List all the ids of tasks used as dependencies of others
];
// Create missing tasks (for dependencies)
.filter(
)
});
}

return fc.set(
taskId: fc.integer({ min: layer * 10, max: layer * 10 + 9 }),
estimatedTime: fc.nat(),
// Curret layer can have dependencies onto any other previous layer
layer !== 0
? fc.set(fc.integer({ min: 0, max: (layer - 1) * 10 + 9 }))
: fc.constant([])
}),
);
}
``````

## Property 1: should keep all the tasks for the scheduled plan

for any valid set of tasks
it should compute a schedule including all the tasks

Written with fast-check:

``````it("should keep all the tasks for the scheduled plan", () => {
fc.assert(
// Arrange / Act

// Assert
})
);
});
``````

## Property 2: should not extend or reduce the duration of tasks

for any valid set of tasks
it should compute a schedule and keep duration untouched

Written with fast-check:

``````it("should not extend or reduce the duration of tasks", () => {
fc.assert(
// Arrange / Act

// Assert
for (const scheduledTask of schedule) {
);
}
})
);
});
``````

## Property 3: should not start any task before all its dependencies ended

for any valid set of tasks
it should compute a schedule following the requested dependencies between tasks

Written with fast-check:

``````it("should not start any task before all its dependencies ended", () => {
fc.assert(
// Arrange / Act

// Assert
for (const scheduledTask of schedule) {
for (const depTaskId of dependencies) {
);
}
}
})
);
});
``````

## Property 4: should start tasks as soon as possible

for any valid set of tasks
it should compute the most optimized schedule

Written with fast-check:

``````it("should start tasks as soon as possible", () => {
fc.assert(
// Arrange / Act

// Assert
for (const scheduledTask of schedule) {
const finishTimeDependencies = dependencies.map((depTaskId) => {
});
const expectedStart =
finishTimeDependencies.length !== 0
? Math.max(...finishTimeDependencies)
: 0;