Skip to content

Commit

Permalink
Migrate tests for fluid.actions
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthaTi committed Jan 17, 2025
1 parent d3cb0c1 commit 97f5574
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 31 deletions.
11 changes: 4 additions & 7 deletions source/fluid/actions.d
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ abstract class FocusSearchAction : NodeSearchAction, Publisher!Focusable {
}

/// Set focus on the given node, if focusable, or the first of its focusable children. This will be done lazily during
/// the next draw.
/// the next draw.
///
/// If focusing the given node is not desired, use `focusRecurseChildren`.
///
Expand Down Expand Up @@ -137,7 +137,7 @@ unittest {

}

/// Set focus on the first of the node's focusable children. This will be done lazily during the next draw.
/// Set focus on the first of the node's focusable children. This will be done lazily during the next draw.
///
/// Params:
/// parent = Container node to search in.
Expand All @@ -158,28 +158,24 @@ FocusRecurseAction focusChild(Node parent) {

}

@("FocusRecurse works")
unittest {

import fluid.space;
import fluid.button;

auto io = new HeadlessBackend;
auto root = vframeButton(
button("", delegate { }),
button("", delegate { }),
delegate { }
);

root.io = io;

// Typical focusRecurse call will focus the button
root.focusRecurse;
root.draw();

assert(root.tree.focus is root);

io.nextFrame;

// If we want to make sure the action descends below the root, we must
root.focusRecurseChildren;
root.draw();
Expand Down Expand Up @@ -252,6 +248,7 @@ ScrollIntoViewAction scrollToTop(Node node) {

}

@("Legacy: ScrollIntoViewAction works (migrated)")
unittest {

import fluid;
Expand Down
58 changes: 34 additions & 24 deletions source/fluid/test_space.d
Original file line number Diff line number Diff line change
Expand Up @@ -747,8 +747,10 @@ auto drawsImage(Node subject) {

bool isTestingImage;
Image targetImage;
bool isTestingArea;
Rectangle targetArea;
bool isTestingStart;
Vector2 targetStart;
bool isTestingSize;
Vector2 targetSize;
bool isTestingColor;
Color targetColor;
bool isTestingHint;
Expand Down Expand Up @@ -776,12 +778,18 @@ auto drawsImage(Node subject) {
}
}

if (isTestingArea) {
assert(equal(targetArea.x, rect.x)
&& equal(targetArea.y, rect.y)
&& equal(targetArea.width, rect.width)
&& equal(targetArea.height, rect.height),
format!"%s should draw image at %s, but draws at %s"(node, targetArea, rect).assertNotThrown);
if (isTestingStart) {
assert(equal(targetStart.x, rect.x)
&& equal(targetStart.y, rect.y),
format!"%s should draw image at %s, but draws at %s"(node, targetStart, rect.start)
.assertNotThrown);
}

if (isTestingSize) {
assert(equal(targetSize.x, rect.w)
&& equal(targetSize.y, rect.h),
format!"%s should draw image of size %s, but draws %s"(node, targetSize, rect.size)
.assertNotThrown);
}

if (isTestingColor) {
Expand All @@ -806,33 +814,28 @@ auto drawsImage(Node subject) {
}

typeof(this) at(Vector2 position) @safe {
isTestingArea = true;
targetArea = Rectangle(position.tupleof, targetImage.size.tupleof);
isTestingStart = true;
targetStart = position;
// TODO DPI
return this;

}

typeof(this) at(typeof(Vector2.tupleof) position) @safe {
isTestingArea = true;
targetArea = Rectangle(position, targetImage.size.tupleof);
// TODO DPI
return at(Vector2(position));
return this;
}

typeof(this) at(Rectangle area) @safe {
isTestingArea = true;
targetArea = area;
// TODO DPI
at(area.start);
isTestingSize = true;
targetSize = area.size;
return this;

}

typeof(this) at(typeof(Rectangle.tupleof) position) @safe {
isTestingArea = true;
targetArea = Rectangle(position);
// TODO DPI
return this;
typeof(this) at(typeof(Rectangle.tupleof) area) @safe {
return at(Rectangle(area));
}

typeof(this) withPalette(Color[] colors...) @safe {
Expand All @@ -855,7 +858,8 @@ auto drawsImage(Node subject) {
return toText(
subject, " should draw an image ",
isTestingImage ? toText(targetImage) : "",
isTestingArea ? toText(" rectangle ", targetArea) : "",
isTestingStart ? toText(" at ", targetStart) : "",
isTestingSize ? toText(" of size ", targetSize) : "",
isTestingColor ? toText(" of color ", targetColor.toHex) : "",
);
}
Expand Down Expand Up @@ -1073,11 +1077,15 @@ auto draws(Node subject) {
}

/// Make sure the selected node doesn't draw anything until another node does.
auto doesNotDraw(Node subject) {
auto doesNotDraw(alias predicate = `a.startsWith("draw")`)(Node subject) {

import std.functional : unaryFun;

bool matched;
string failedName;

alias fun = unaryFun!predicate;

return drawsWildcard!((node, methodName) {

// Test failed, skip checks
Expand All @@ -1103,7 +1111,7 @@ auto doesNotDraw(Node subject) {
return true;
}

if (isSubject && methodName.startsWith("draw")) {
if (isSubject && fun(methodName)) {
failedName = methodName;
return false;
}
Expand All @@ -1115,6 +1123,8 @@ auto doesNotDraw(Node subject) {

}

alias doesNotDrawImages = doesNotDraw!`a.among("drawImage", "drawHintedImage")`;

/// Ensure the node emits a debug signal.
auto emits(Node subject, string name) {

Expand Down
56 changes: 56 additions & 0 deletions tests/actions/scroll_into_view_action.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module actions.scroll_into_view_action;

import std.math;
import std.array;
import std.range;
import std.algorithm;

import fluid;

@safe:

@("ScrollIntoViewAction works")
unittest {

const viewportHeight = 10;

Label[3] labels;

auto frame = vscrollFrame(
.layout!(1, "fill"),
labels[0] = label("a"),
labels[1] = label("b"),
labels[2] = label("c"),
);
auto root = sizeLock!testSpace(
.nullTheme,
.sizeLimit(10, viewportHeight),
.cropViewport,
frame
);

frame.scrollBar.width = 0; // TODO replace this with scrollBar.hide()

// Prepare scrolling
// Note: Changes made when scrolling will be visible during the next frame
frame.children[1].scrollIntoView;
root.draw();

// No theme so everything is as compact as it can be: the first label should be at the very top
// It is reasonable to assume the text will be larger than 10 pixels (viewport height)
// Other text will not render, since it's offscreen
root.drawAndAssert(
labels[0].doesNotDrawImages(),
labels[1].drawsImage().at(0, viewportHeight - labels[1].text.size.y),
labels[2].doesNotDrawImages(),
);
// TODO Because the label was hidden below the viewport, Fluid will align the bottom of the selected node with the
// viewport which probably isn't appropriate in case *like this* where it should reveal the top of the node.

// auto texture1 = io.textures.front;
// assert(isClose(texture1.position.y + texture1.height, viewportHeight));
assert(isClose(frame.scroll, (frame.scrollMax + 10) * 2/3 - 10));

// TODO more tests. Scrolling while already in the viewport, scrolling while partially out of the view, etc.

}

0 comments on commit 97f5574

Please sign in to comment.