Skip to content

Implemented lower and upper constraint bounds#75

Merged
Seldaek merged 21 commits intocomposer:masterfrom
Toflar:feature/constraint-bounds
Apr 16, 2020
Merged

Implemented lower and upper constraint bounds#75
Seldaek merged 21 commits intocomposer:masterfrom
Toflar:feature/constraint-bounds

Conversation

@Toflar
Copy link
Copy Markdown
Contributor

@Toflar Toflar commented Jan 5, 2020

Implementation for #72 :)

@codecov-io
Copy link
Copy Markdown

codecov-io commented Jan 5, 2020

Codecov Report

Merging #75 into master will decrease coverage by 2.36%.
The diff coverage is 84.26%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master      #75      +/-   ##
============================================
- Coverage     96.89%   94.52%   -2.37%     
- Complexity      206      247      +41     
============================================
  Files             7        8       +1     
  Lines           386      475      +89     
============================================
+ Hits            374      449      +75     
- Misses           12       26      +14     
Impacted Files Coverage Δ Complexity Δ
src/Constraint/EmptyConstraint.php 71.42% <0.00%> (-28.58%) 7.00 <2.00> (+2.00) ⬇️
src/Constraint/Bound.php 65.51% <65.51%> (ø) 17.00 <17.00> (?)
src/Constraint/Constraint.php 100.00% <100.00%> (ø) 38.00 <11.00> (+11.00)
src/Constraint/MultiConstraint.php 100.00% <100.00%> (ø) 27.00 <11.00> (+11.00)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 811c569...79ad211. Read the comment docs.

Comment thread tests/Constraint/ConstraintTest.php Outdated
Comment thread tests/Constraint/ConstraintTest.php Outdated
@Seldaek
Copy link
Copy Markdown
Member

Seldaek commented Jan 13, 2020

Stopping the review because I notice from the tests it seems quite off from what we'd need to achieve. The operator of the constraint must be taken into account.

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 13, 2020

So what's the actualy goal then here? I thought the goal was to get the normalized bounds from a contstraint so you can version_compare() yourself, in which case the constraint is not needed.

@Seldaek
Copy link
Copy Markdown
Member

Seldaek commented Jan 13, 2020

Yes that's the goal, but a constraint like 1.0.0 has upper and lower bounds both 1.0.0.0, your patch doesn't do this.

While a constraint like ^2.3 has lower bound 2.3.0.0 and upper 2.9999999.9999999.9999999. Maybe I missed something here, but I don't really see how it allows us to do this?

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 14, 2020

I see. Closing then.

@Toflar Toflar closed this Jan 14, 2020
@Toflar Toflar reopened this Jan 14, 2020
@Toflar Toflar force-pushed the feature/constraint-bounds branch from 65c3f71 to 2523df6 Compare January 14, 2020 17:13
@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 14, 2020

Okay, let's check again @Seldaek and @naderman :)

Comment thread src/Constraint/Constraint.php
Comment thread src/Constraint/BoundsProvidingInterface.php Outdated
Comment thread src/Constraint/BoundsProvidingInterface.php Outdated
Comment thread tests/Constraint/ConstraintTest.php Outdated
@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 15, 2020

In case we agree that the current state is the correct way to go, I'd finish this by implementing it on the MultiConstraint with some integration tests together with the VersionParser.

@Seldaek
Copy link
Copy Markdown
Member

Seldaek commented Jan 16, 2020

I think so :)

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 16, 2020

Here we go, looks pretty good imho :) Ping @Seldaek @naderman

Comment thread src/Constraint/MultiConstraint.php Outdated
Comment thread src/Constraint/MultiConstraint.php Outdated
Comment thread src/Constraint/MultiConstraint.php Outdated
@Seldaek
Copy link
Copy Markdown
Member

Seldaek commented Jan 17, 2020

I pushed a test in the branch (sorry broke 5.3 don't wanna push again if you're back working on it), and added another test locally but it fails so I thought I'll let you add it and try to make it pass:

    public function testMultipleMultiConstraintsMergingWithGaps()
    {
        $versionParser = new VersionParser();
        $constraints = [
            '^7.1.15 || ^7.2.3',
            '^7.2.2',
        ];
        foreach ($constraints as &$constraint) {
            $constraint = $versionParser->parseConstraints($constraint);
        }

        $constraint = new MultiConstraint($constraints);

        $this->assertSame(array('>=', '7.2.3.0.dev'), $constraint->getLowerBound(), 'Expected lower bound does not match');
        $this->assertSame(array('<', '8.0.0.0.dev'), $constraint->getUpperBound(), 'Expected upper bound does not match');
    }

The lower bound returned is >=7.1.15.0.dev which is correct for the first constraint but not for the set of constraints.

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 17, 2020

No prob, will add that test as well.

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 17, 2020

@Seldaek your test is just wrong. The reference thing doesn't work because it would nest constraints and also the lower bound in that case is 7.2.2.0.dev not 7.2.3.0.dev 😄
Adjusted in my latest try though.

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 17, 2020

So I've removed the black magic, the additional interface is gone as well and we now have a proper Bound object that represents a bound and also does the comparison to another bound.
Now I am happy 😄

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 17, 2020

I also got rid of the infinity thing and used PHP_INT_MAX because otherwise everybody would need to handle the infinity thing and because there are no Composer libraries loaded in our autload.php case it would mean to compare to inf which is kind of nonsense.

@Seldaek
Copy link
Copy Markdown
Member

Seldaek commented Jan 17, 2020

You're right it should have been >=7.2.2.0.dev as lower bound, but I don't get what you mean by "The reference thing doesn't work because it would nest constraints". Anyway I see the new version returns 7.2.2 so I guess you fixed it?

@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Jan 17, 2020

I fixed your test, yes :)

@Toflar Toflar changed the title Implemented first shot at lower and upper constraint bounds Implemented lower and upper constraint bounds Jan 17, 2020
@Toflar Toflar force-pushed the feature/constraint-bounds branch from e09b73c to 68340f8 Compare April 16, 2020 09:14
@Toflar
Copy link
Copy Markdown
Contributor Author

Toflar commented Apr 16, 2020

After discussion with @Seldaek and @naderman, we agreed that the whole comparison logic is probably way too specific and out of scope for the semver component.
I've updated the PR accordingly and rebased it onto master. It now contains only the bounds logic, so this should be ready for a final review. Failing tests seem unrelated (probably just needs a restart). Want me to squash or will you be squash merging anyway?

Comment thread src/Constraint/Bound.php Outdated
return $this->isInclusive;
}

public function isLowerMost()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "isLowest"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe "isMin"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "isZero"

Comment thread src/Constraint/Bound.php Outdated
return $this->getVersion() === '0' && $this->isInclusive();
}

public function isUpperMost()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "isHighest"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or if you go for isMin, isMax?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "isPositiveInfinity()"

Comment thread src/Constraint/Bound.php Outdated
/**
* @return self
*/
public static function upperMost()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called positiveInfinity? or something? or max? "upperMost" is pretty weird.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "positiveInfinity()"

Comment thread src/Constraint/Bound.php Outdated
/**
* @return self
*/
public static function lowerMost()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "zero()"

@Seldaek Seldaek merged commit c410ec3 into composer:master Apr 16, 2020
@Toflar Toflar deleted the feature/constraint-bounds branch April 16, 2020 11:43
Comment thread src/Constraint/Bound.php
}

// Question we're answering here is "am I higher than $other?"
return '>' === $operator ? $other->isInclusive() : !$other->isInclusive();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks weird to be that $this->isInclusive() is never taken into account. Is this correct ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh I don't know. I've been messing with this code for too long but there are lots of tests in the MultiConstraintTest which uses the compareTo() method internally. So maybe we were missing a constellation that requires a test? Would be great if you could provide that. More eyes is always better :)

Copy link
Copy Markdown
Member

@naderman naderman Apr 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$this->isInclusive is implicitly checked when we do ($this == $other) above.

When we come to this part of the code, the version on both bounds is the same, so the following table is the result (x means, the bounds are identical, so the early return at the top of the function prevents this from mattering):

expression this.isInclusive other.isInclusive result
this.compareTo(other, >) 0 0 x
this.compareTo(other, >) 0 1 1
this.compareTo(other, >) 1 0 0
this.compareTo(other, >) 1 1 x
this.compareTo(other, <) 0 0 x
this.compareTo(other, <) 0 1 0
this.compareTo(other, <) 1 0 1
this.compareTo(other, <) 1 1 x

So you can see that the expression is correct. But since we exclude a large part of the variations with early returns, an expression like '>' === $operator ? !$this->isInclusive() : $this->isInclusive() would be just as correct, since we already made sure that $this->isInclusive() != $other->isInclusive() once it gets to this section of the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants