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

Subcontracting through the factory pattern loses track of context #236

Closed
mlhaufe opened this issue Aug 20, 2022 · 2 comments · Fixed by #237
Closed

Subcontracting through the factory pattern loses track of context #236

mlhaufe opened this issue Aug 20, 2022 · 2 comments · Fixed by #237
Assignees
Labels
bug Something isn't working feature/contract The Contract declaration
Milestone

Comments

@mlhaufe
Copy link
Contributor

mlhaufe commented Aug 20, 2022

Reduced test case:

const factoryContract = new Contract<Factory>();

@Contracted(factoryContract)
class Factory {
    child(value: string) { return new Child(value); }
    @override
    toString() { throw new TypeError('MUST OVERRIDE'); }
}

const childContract = new Contract<Child>({
    [extend]: factoryContract,
    [invariant](self) { return self.value.length === 1; }
});

@Contracted(childContract)
class Child extends Factory {
    #value: string;

    constructor(value: string) {
        super();
        this.#value = value;
    }

    get value() { return this.#value; }

    @override
    override toString() { return `'${this.#value}'`; }
}

// PASS
test('Construct Child', () => {
    const f = new Factory(),
        c = f.child('a');

    expect(c).toBeInstanceOf(Child);
    expect(c.value).toBe('a');
});

// FAIL
test('Char[toString]()', () => {
    const f = new Factory();
    expect(f.child('a').toString()).toBe('\'a\'');
    expect(() => {
        f.child('abc');
    }).toThrow(AssertionError);
});

Calling toString in the second test causes the invariant to fail:

TypeError: Cannot read properties of undefined (reading 'length')
[invariant](self) { return self.value.length === 1; }

What's strange here is that the getter value seems to work (test 1) but toString seems to not be operating on Child.

@mlhaufe mlhaufe added bug Something isn't working feature/contract The Contract declaration labels Aug 20, 2022
@mlhaufe mlhaufe added this to the v0.24.0 milestone Aug 20, 2022
@mlhaufe mlhaufe self-assigned this Aug 20, 2022
@mlhaufe
Copy link
Contributor Author

mlhaufe commented Aug 20, 2022

Even further reduced test case:

// PASS
test('Construct Child', () => {
    const c = new Child('a');

    expect(c).toBeInstanceOf(Child);
    expect(c.value).toBe('a');
});

// FAIL
test('Factory Construct Child', () => {
    const f = new Factory(),
          c = f.child('a');

    expect(c).toBeInstanceOf(Child);
    expect(c.value).toBe('a');
});

@mlhaufe
Copy link
Contributor Author

mlhaufe commented Aug 20, 2022

I wonder if a fix for this would also fix #231

mlhaufe added a commit that referenced this issue Aug 21, 2022
@mlhaufe mlhaufe mentioned this issue Aug 21, 2022
mlhaufe added a commit that referenced this issue Aug 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working feature/contract The Contract declaration
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant