1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-08 23:24:19 +00:00

Component: Add some basic unit tests

This commit is contained in:
Anthony Nicholls 2025-04-28 18:09:55 +01:00 committed by Anthony Nicholls
parent 961ff32b9e
commit 5ec4d85d82

View file

@ -3205,4 +3205,536 @@ AccessibilityHandler* Component::getAccessibilityHandler()
return accessibilityHandler.get();
}
#if JUCE_UNIT_TESTS
struct ComponentTests : public UnitTest
{
ComponentTests()
: UnitTest ("Component", UnitTestCategories::gui)
{
}
struct TestComponent : Component
{
void paint (Graphics& g) final
{
lastClipBounds = g.getClipBounds();
++numPaintCalls;
}
int numPaintCalls = 0;
Rectangle<int> lastClipBounds;
};
void paintComponentBounds (Component& componentToRepaint)
{
auto* topLevelComponent = componentToRepaint.getTopLevelComponent();
topLevelComponent->createComponentSnapshot (topLevelComponent->getLocalArea (&componentToRepaint, componentToRepaint.getLocalBounds()));
}
void runTest() override
{
ScopedJuceInitialiser_GUI libraryInitialiser;
beginTest ("Painting a parents bounds paints both parent and child");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.reduced (25));
parent->addAndMakeVisible (*child);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child->numPaintCalls, 0);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Non-opaque children require their parent to repaint");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.reduced (25));
parent->addAndMakeVisible (*child);
paintComponentBounds (*child);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Opaque children don't require their parent to repaint");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.reduced (25));
child->setOpaque (true);
parent->addAndMakeVisible (*child);
paintComponentBounds (*child);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Opaque children don't require their parent to repaint (even when the parent uses setPaintingIsUnclipped (true))");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setPaintingIsUnclipped (true);
parent->setBounds (bounds);
child->setBounds (bounds.reduced (25));
child->setOpaque (true);
parent->addAndMakeVisible (*child);
paintComponentBounds (*child);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("A partially obscured parent will repaint with reduced clip bounds");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.removeFromTop (50));
child->setOpaque (true);
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 1);
expect (parent->lastClipBounds == bounds);
}
beginTest ("A totally obscured parent will never repaint");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds.removeFromTop (50));
child1->setOpaque (true);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
child2->setOpaque (true);
parent->addAndMakeVisible (*child2);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child1->numPaintCalls, 1);
expectEquals (child2->numPaintCalls, 1);
}
beginTest ("An opaque component will hide sibling components behind it");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
const auto child3 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
child2->setOpaque (true);
parent->addAndMakeVisible (*child2);
child3->setBounds (bounds);
parent->addAndMakeVisible (*child3);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child1->numPaintCalls, 0);
expectEquals (child2->numPaintCalls, 1);
expectEquals (child3->numPaintCalls, 1);
}
beginTest ("An opaque component will hide parent-sibling components behind it");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
const auto child3 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
parent->addAndMakeVisible (*child2);
child3->setBounds (bounds);
child3->setOpaque (true);
child2->addAndMakeVisible (*child3);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child1->numPaintCalls, 0);
expectEquals (child2->numPaintCalls, 0);
expectEquals (child3->numPaintCalls, 1);
}
beginTest ("An opaque component will reduce the clip bounds of sibling components behind it");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
const auto child3 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds.removeFromTop (50));
child2->setOpaque (true);
parent->addAndMakeVisible (*child2);
child3->setBounds (child1->getBounds());
parent->addAndMakeVisible (*child3);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child1->numPaintCalls, 1);
expectEquals (child2->numPaintCalls, 1);
expectEquals (child3->numPaintCalls, 1);
expect (child1->lastClipBounds == bounds);
expect (child3->lastClipBounds == child3->getBounds());
}
beginTest ("A child component will be clipped when painted");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.reduced (25));
parent->addAndMakeVisible (*child);
expect (parent->lastClipBounds.isEmpty());
expect (child->lastClipBounds.isEmpty());
paintComponentBounds (*parent);
expect (parent->lastClipBounds == parent->getLocalBounds());
expect (child->lastClipBounds == child->getLocalBounds());
}
beginTest ("setPaintingIsUnclipped (true) will cause a child to have its parents clip bounds");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.reduced (25));
child->setPaintingIsUnclipped (true);
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expect (child->lastClipBounds == child->getLocalArea (parent.get(), parent->getLocalBounds()));
}
beginTest ("Opaque components hide parents that use setPaintingIsUnclipped (true)");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
parent->setPaintingIsUnclipped (true);
child->setBounds (bounds);
child->setOpaque (true);
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Opaque components hide parents that use setPaintingIsUnclipped (true)");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
parent->setPaintingIsUnclipped (true);
child->setBounds (bounds);
child->setOpaque (true);
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Invisible child components will not be considered opaque");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds);
child->setOpaque (true);
parent->addChildComponent (*child);
expect (! child->isVisible());
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 0);
}
beginTest ("Invisible sibling components will not be considered opaque");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
child2->setOpaque (true);
parent->addChildComponent (*child2);
expect ( child1->isVisible());
expect (! child2->isVisible());
paintComponentBounds (*parent);
expectEquals (child1->numPaintCalls, 1);
expectEquals (child2->numPaintCalls, 0);
}
beginTest ("Components with an invisible parent will not be considered opaque");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
const auto grandchild = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds);
parent->addChildComponent (*child);
grandchild->setBounds (bounds);
grandchild->setOpaque (true);
child->addAndMakeVisible (*grandchild);
expect (! child->isVisible());
expect (grandchild->isVisible());
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 0);
expectEquals (grandchild->numPaintCalls, 0);
}
beginTest ("Components with a width of 0 will not have their paint function called");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.withWidth (0));
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 0);
}
beginTest ("Components with a height of 0 will not have their paint function called");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds.withHeight (0));
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 0);
}
beginTest ("Transparent components will not be considered opaque");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds);
child->setOpaque (true);
child->setAlpha (0.5f);
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Opaque components will only be considered opaque up to a transparent parent");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
child1->setAlpha (0.5f);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
child2->setOpaque (true);
child1->addAndMakeVisible (*child2);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child1->numPaintCalls, 0);
expectEquals (child2->numPaintCalls, 1);
}
beginTest ("Transformed components will not be considered opaque");
{
const auto parent = std::make_unique<TestComponent>();
const auto child = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child->setBounds (bounds);
child->setOpaque (true);
child->setTransform (AffineTransform::rotation (degreesToRadians (45.0f)));
parent->addAndMakeVisible (*child);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child->numPaintCalls, 1);
}
beginTest ("Opaque components will only be considered opaque up to a transformed parent");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
child1->setTransform (AffineTransform::rotation (degreesToRadians (45.0f)));
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
child2->setOpaque (true);
child1->addAndMakeVisible (*child2);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 1);
expectEquals (child1->numPaintCalls, 0);
expectEquals (child2->numPaintCalls, 1);
}
beginTest ("Nested opaque components prevent parents from being painted");
{
const auto parent = std::make_unique<TestComponent>();
const auto child1 = std::make_unique<TestComponent>();
const auto child2 = std::make_unique<TestComponent>();
Rectangle<int> bounds { 0, 0, 100, 100 };
parent->setBounds (bounds);
child1->setBounds (bounds);
child1->setOpaque (true);
parent->addAndMakeVisible (*child1);
child2->setBounds (bounds);
child2->setOpaque (true);
child1->addAndMakeVisible (*child2);
paintComponentBounds (*parent);
expectEquals (parent->numPaintCalls, 0);
expectEquals (child1->numPaintCalls, 0);
expectEquals (child2->numPaintCalls, 1);
}
}
};
static ComponentTests componentTests;
#endif
} // namespace juce