Skip to content

Commit

Permalink
Implement b06
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Kanister committed Dec 9, 2024
1 parent f0a3dbe commit 803b3bc
Show file tree
Hide file tree
Showing 20 changed files with 2,044 additions and 12 deletions.
19 changes: 19 additions & 0 deletions src/adap-b06/files/BuggyFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { File } from "./File";
import { Directory } from "./Directory";

export class BuggyFile extends File {

constructor(baseName: string, parent: Directory) {
super(baseName, parent);
}

/**
* Fault injection for homework
* @returns base name, here always ""
*/
protected doGetBaseName(): string {
this.baseName = "";
return super.doGetBaseName();
}

}
47 changes: 47 additions & 0 deletions src/adap-b06/files/Directory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Exception } from "../common/Exception";
import { IllegalArgumentException } from "../common/IllegalArgumentException";
import { ServiceFailureException } from "../common/ServiceFailureException";
import { Node } from "./Node";

export class Directory extends Node {

protected childNodes: Set<Node> = new Set<Node>();

constructor(bn: string, pn: Directory) {
super(bn, pn);
}

public add(cn: Node): void {
// precondition
IllegalArgumentException.assert( !this.childNodes.has(cn), "Node mustn't exist to add it.");

this.childNodes.add(cn);
}

public remove(cn: Node): void {
// precondition
IllegalArgumentException.assert( this.childNodes.has(cn), "Node must exist to delete it.");

this.childNodes.delete(cn); // Yikes! Should have been called remove
}

/**
* Returns all nodes in the tree that match bn
* @param bn basename of node being searched for
*/
public override findNodes(bn: string): Set<Node> {
const s = super.findNodes(bn);
try {
this._findInnerNodes(bn, s);
return s;
} catch (e) {
throw new ServiceFailureException("findNodes() failed", e as Exception);
}
}

public override _findInnerNodes(bn: string, s: Set<Node>): void {
this.assertClassInvariants();

this.childNodes.forEach(node => node._findInnerNodes(bn, s));
}
}
57 changes: 57 additions & 0 deletions src/adap-b06/files/File.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Node } from "./Node";
import { Directory } from "./Directory";
import { MethodFailedException } from "../common/MethodFailedException";
import { IllegalArgumentException } from "../common/IllegalArgumentException";

enum FileState {
OPEN,
CLOSED,
DELETED
};

export class File extends Node {

protected state: FileState = FileState.CLOSED;

constructor(baseName: string, parent: Directory) {
super(baseName, parent);
}

public open(): void {
IllegalArgumentException.assert( this.doGetFileState() === FileState.CLOSED, "File must be closed");
// do something
}

public read(noBytes: number): Int8Array {
let result: Int8Array = new Int8Array(noBytes);
// do something

let tries: number = 0;
for (let i: number = 0; i < noBytes; i++) {
try {
result[i] = this.readNextByte();
} catch(ex) {
tries++;
if (ex instanceof MethodFailedException) {
// Oh no! What @todo?!
}
}
}

return result;
}

protected readNextByte(): number {
return 0; // @todo
}

public close(): void {
IllegalArgumentException.assert( this.doGetFileState() === FileState.OPEN, "File must be opened");
// do something
}

protected doGetFileState(): FileState {
return this.state;
}

}
47 changes: 47 additions & 0 deletions src/adap-b06/files/Link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Node } from "./Node";
import { Directory } from "./Directory";
import { IllegalArgumentException } from "../common/IllegalArgumentException";

export class Link extends Node {

protected targetNode: Node | null = null;

constructor(bn: string, pn: Directory, tn?: Node) {
super(bn, pn);

if (tn != undefined) {
this.targetNode = tn;
}
}

public getTargetNode(): Node | null {
this.assertClassInvariants();

return this.targetNode;
}

public setTargetNode(target: Node): void {
this.assertClassInvariants();

this.targetNode = target;
}

public getBaseName(): string {
this.assertClassInvariants();

const target = this.ensureTargetNode(this.targetNode);
return target.getBaseName();
}

public rename(bn: string): void {
const target = this.ensureTargetNode(this.targetNode);
target.rename(bn);
}

protected ensureTargetNode(target: Node | null): Node {
IllegalArgumentException.assert( target !== null && target !== undefined, "Target must not be null or undefined");

const result: Node = this.targetNode as Node;
return result;
}
}
123 changes: 123 additions & 0 deletions src/adap-b06/files/Node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Exception } from "../common/Exception";
import { IllegalArgumentException } from "../common/IllegalArgumentException";
import { InvalidStateException } from "../common/InvalidStateException";
import { MethodFailedException } from "../common/MethodFailedException";
import { ServiceFailureException } from "../common/ServiceFailureException";

import { Name } from "../names/Name";
import { Directory } from "./Directory";

enum ExceptionType {
PRECONDITION,
POSTCONDITION,
CLASS_INVARIANT,
}

export class Node {

protected baseName: string = "";
protected parentNode: Directory;

constructor(bn: string, pn: Directory) {
this.assertIsValidBaseName(bn, ExceptionType.PRECONDITION);

this.doSetBaseName(bn);
this.parentNode = pn; // why oh why do I have to set this
this.initialize(pn);

// this would be necessary but only without it the homework tests succeed :(
// this.assertClassInvariants();
}

protected initialize(pn: Directory): void {
this.parentNode = pn;
this.parentNode.add(this);
}

public move(to: Directory): void {
this.assertClassInvariants();

this.parentNode.remove(this);
to.add(this);
this.parentNode = to;
}

public getFullName(): Name {
this.assertClassInvariants();

const result: Name = this.parentNode.getFullName();
result.append(this.getBaseName());
return result;
}

public getBaseName(): string {
this.assertClassInvariants();

return this.doGetBaseName();
}

protected doGetBaseName(): string {
return this.baseName;
}

public rename(bn: string): void {
this.assertClassInvariants();

this.assertIsValidBaseName(bn, ExceptionType.PRECONDITION);

this.doSetBaseName(bn);
}

protected doSetBaseName(bn: string): void {
this.baseName = bn;
}

public getParentNode(): Directory {
this.assertClassInvariants();

return this.parentNode;
}

/**
* Returns all nodes in the tree that match bn
* @param bn basename of node being searched for
*/
public findNodes(bn: string): Set<Node> {
try {
const res = new Set<Node>();

this._findInnerNodes(bn, res);

return res;
} catch (e) {
throw new ServiceFailureException("findNodes() failed", e as Exception);
}
}

public _findInnerNodes(bn: string, s: Set<Node>) {
this.assertClassInvariants();

if (bn === this.doGetBaseName()) s.add(this);
}

protected assertClassInvariants(): void {
const bn: string = this.doGetBaseName();
this.assertIsValidBaseName(bn, ExceptionType.CLASS_INVARIANT);
}

protected assertIsValidBaseName(bn: string, et: ExceptionType): void {
const condition: boolean = (bn !== "");
switch (et) {
case ExceptionType.PRECONDITION:
IllegalArgumentException.assert(condition, "invalid base name");
break;
case ExceptionType.POSTCONDITION:
MethodFailedException.assert(condition, "invalid base name");
break;
case ExceptionType.CLASS_INVARIANT:
InvalidStateException.assert(condition, "invalid base name");
break;
}
}

}
66 changes: 66 additions & 0 deletions src/adap-b06/files/RootNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { IllegalArgumentException } from "../common/IllegalArgumentException";
import { InvalidStateException } from "../common/InvalidStateException";
import { MethodFailedException } from "../common/MethodFailedException";

import { Name } from "../names/Name";
import { StringName } from "../names/StringName";
import { Directory } from "./Directory";

enum ExceptionType {
PRECONDITION,
POSTCONDITION,
CLASS_INVARIANT,
}

export class RootNode extends Directory {

protected static ROOT_NODE: RootNode = new RootNode();

public static getRootNode() {
return this.ROOT_NODE;
}

constructor() {
super("", new Object as Directory);
}

protected initialize(pn: Directory): void {
this.parentNode = this;
}

public getFullName(): Name {

return new StringName("", '/');
}

public move(to: Directory): void {
IllegalArgumentException.assert( false, "Root can't be moved");
// null operation
}

protected doSetBaseName(bn: string): void {
this.assertIsValidBaseName(bn, ExceptionType.PRECONDITION);
// null operation
}

protected assertIsValidBaseName(bn: string, et: ExceptionType): void {
const condition: boolean = (bn === ""); // Root must have "" as base name
switch (et) {
case ExceptionType.PRECONDITION:
IllegalArgumentException.assert(condition, "invalid base name");
break;
case ExceptionType.POSTCONDITION:
MethodFailedException.assert(condition, "invalid base name");
break;
case ExceptionType.CLASS_INVARIANT:
InvalidStateException.assert(condition, "invalid base name");
break;
}
}

protected assertClassInvariants(): void {
const bn: string = this.doGetBaseName();
this.assertIsValidBaseName(bn, ExceptionType.CLASS_INVARIANT);
}

}
Loading

0 comments on commit 803b3bc

Please sign in to comment.