blob: 8de95f9a428be336ae4ed047cfa8ebe5f41ac49c [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "apps/moterm/moterm_model.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
TEST(MotermModelTest, Position) {
MotermModel::Position def;
EXPECT_EQ(0, def.row);
EXPECT_EQ(0, def.column);
MotermModel::Position pos(12, 34);
EXPECT_EQ(12, pos.row);
EXPECT_EQ(34, pos.column);
}
TEST(MotermModelTest, Size) {
MotermModel::Size def;
EXPECT_EQ(0u, def.rows);
EXPECT_EQ(0u, def.columns);
MotermModel::Size size(12, 34);
EXPECT_EQ(12u, size.rows);
EXPECT_EQ(34u, size.columns);
}
TEST(MotermModelTest, Rectangle) {
MotermModel::Rectangle def;
EXPECT_EQ(0, def.position.row);
EXPECT_EQ(0, def.position.column);
EXPECT_EQ(0u, def.size.rows);
EXPECT_EQ(0u, def.size.columns);
EXPECT_TRUE(def.IsEmpty());
MotermModel::Rectangle rect1(1, 2, 34, 56);
EXPECT_EQ(1, rect1.position.row);
EXPECT_EQ(2, rect1.position.column);
EXPECT_EQ(34u, rect1.size.rows);
EXPECT_EQ(56u, rect1.size.columns);
EXPECT_FALSE(rect1.IsEmpty());
MotermModel::Rectangle rect2(1, 2, 0, 0);
EXPECT_EQ(1, rect2.position.row);
EXPECT_EQ(2, rect2.position.column);
EXPECT_EQ(0u, rect2.size.rows);
EXPECT_EQ(0u, rect2.size.columns);
EXPECT_TRUE(rect2.IsEmpty());
MotermModel::Rectangle rect3(0, 0, 1, 2);
EXPECT_EQ(0, rect3.position.row);
EXPECT_EQ(0, rect3.position.column);
EXPECT_EQ(1u, rect3.size.rows);
EXPECT_EQ(2u, rect3.size.columns);
EXPECT_FALSE(rect3.IsEmpty());
MotermModel::Rectangle rect4(1, 2, 3, 0);
EXPECT_EQ(1, rect4.position.row);
EXPECT_EQ(2, rect4.position.column);
EXPECT_EQ(3u, rect4.size.rows);
EXPECT_EQ(0u, rect4.size.columns);
EXPECT_TRUE(rect4.IsEmpty());
MotermModel::Rectangle rect5(1, 2, 0, 3);
EXPECT_EQ(1, rect5.position.row);
EXPECT_EQ(2, rect5.position.column);
EXPECT_EQ(0u, rect5.size.rows);
EXPECT_EQ(3u, rect5.size.columns);
EXPECT_TRUE(rect5.IsEmpty());
}
TEST(MotermModelTest, Color) {
MotermModel::Color def;
EXPECT_EQ(0u, def.red);
EXPECT_EQ(0u, def.green);
EXPECT_EQ(0u, def.blue);
MotermModel::Color color(1, 234, 56);
EXPECT_EQ(1u, color.red);
EXPECT_EQ(234u, color.green);
EXPECT_EQ(56u, color.blue);
}
TEST(MotermModelTest, CharacterInfo) {
MotermModel::CharacterInfo char_info(65, MotermModel::kAttributesBold,
MotermModel::Color(12, 34, 56),
MotermModel::Color(123, 45, 67));
EXPECT_EQ(65u, char_info.code_point);
EXPECT_EQ(MotermModel::kAttributesBold, char_info.attributes);
EXPECT_EQ(12u, char_info.foreground_color.red);
EXPECT_EQ(34u, char_info.foreground_color.green);
EXPECT_EQ(56u, char_info.foreground_color.blue);
EXPECT_EQ(123u, char_info.background_color.red);
EXPECT_EQ(45u, char_info.background_color.green);
EXPECT_EQ(67u, char_info.background_color.blue);
}
TEST(MotermModelTest, StateChanges) {
MotermModel::StateChanges state_changes;
EXPECT_FALSE(state_changes.cursor_changed);
EXPECT_EQ(0u, state_changes.bell_count);
EXPECT_TRUE(state_changes.dirty_rect.IsEmpty());
EXPECT_FALSE(state_changes.IsDirty());
// Should be the same after reset.
state_changes.Reset();
EXPECT_FALSE(state_changes.cursor_changed);
EXPECT_EQ(0u, state_changes.bell_count);
EXPECT_TRUE(state_changes.dirty_rect.IsEmpty());
EXPECT_FALSE(state_changes.IsDirty());
state_changes.cursor_changed = true;
EXPECT_TRUE(state_changes.IsDirty());
state_changes.Reset();
EXPECT_FALSE(state_changes.cursor_changed);
EXPECT_FALSE(state_changes.IsDirty());
state_changes.bell_count++;
EXPECT_TRUE(state_changes.IsDirty());
state_changes.Reset();
EXPECT_EQ(0u, state_changes.bell_count);
EXPECT_FALSE(state_changes.IsDirty());
state_changes.dirty_rect = MotermModel::Rectangle(1, 2, 34, 56);
EXPECT_TRUE(state_changes.IsDirty());
state_changes.Reset();
EXPECT_TRUE(state_changes.dirty_rect.IsEmpty());
EXPECT_FALSE(state_changes.IsDirty());
}
TEST(MotermModelTest, Basic) {
MotermModel model(MotermModel::Size(43, 132), MotermModel::Size(25, 80),
nullptr);
MotermModel::Size size = model.GetSize();
EXPECT_EQ(25u, size.rows);
EXPECT_EQ(80u, size.columns);
// The cursor should start out at the upper-left (and be visible).
MotermModel::Position cursor_pos = model.GetCursorPosition();
EXPECT_EQ(0, cursor_pos.row);
EXPECT_EQ(0, cursor_pos.column);
EXPECT_TRUE(model.GetCursorVisibility());
MotermModel::StateChanges state_changes;
EXPECT_FALSE(state_changes.IsDirty());
// Print "XYZ" in bright (bold) green on red.
static const char kXYZ[] = "\x1b[1;32;41mXYZ";
model.ProcessInput(kXYZ, sizeof(kXYZ) - 1, &state_changes);
EXPECT_TRUE(state_changes.IsDirty());
EXPECT_TRUE(state_changes.cursor_changed);
EXPECT_EQ(0u, state_changes.bell_count);
EXPECT_FALSE(state_changes.dirty_rect.IsEmpty());
// The model has some flexibility in the size of the dirty rectangle (it may
// over-report), but it should contain the actually-dirty part.
EXPECT_LE(state_changes.dirty_rect.position.row, 0);
EXPECT_LE(state_changes.dirty_rect.position.column, 0);
EXPECT_GE(state_changes.dirty_rect.size.rows, 1u);
EXPECT_GE(state_changes.dirty_rect.size.columns, 3u);
// Get the 'Y'.
MotermModel::CharacterInfo char_info =
model.GetCharacterInfoAt(MotermModel::Position(0, 1));
EXPECT_EQ(static_cast<uint32_t>('Y'), char_info.code_point);
EXPECT_EQ(MotermModel::kAttributesBold, char_info.attributes);
// The foreground should be (bright) green-ish; this is a guess at what that
// means.
EXPECT_GE(char_info.foreground_color.green, 100u);
EXPECT_GE(char_info.foreground_color.green / 2,
char_info.foreground_color.red);
EXPECT_GE(char_info.foreground_color.green / 2,
char_info.foreground_color.blue);
// The background_color should be (non-bright) red-ish.
EXPECT_GE(char_info.background_color.red, 50u);
EXPECT_GE(char_info.background_color.red / 2,
char_info.background_color.green);
EXPECT_GE(char_info.background_color.red / 2,
char_info.background_color.blue);
state_changes.Reset();
EXPECT_FALSE(state_changes.IsDirty());
// Now ring the bell three times.
static const char kBellBellBell[] = "\a\a\a";
model.ProcessInput(kBellBellBell, sizeof(kBellBellBell) - 1, &state_changes);
EXPECT_TRUE(state_changes.IsDirty());
EXPECT_FALSE(state_changes.cursor_changed);
EXPECT_EQ(3u, state_changes.bell_count);
EXPECT_TRUE(state_changes.dirty_rect.IsEmpty());
model.SetSize(MotermModel::Size(43, 132), false);
size = model.GetSize();
EXPECT_EQ(43u, size.rows);
EXPECT_EQ(132u, size.columns);
model.SetSize(MotermModel::Size(40, 100), true);
size = model.GetSize();
EXPECT_EQ(40u, size.rows);
EXPECT_EQ(100u, size.columns);
}
TEST(MotermModelTest, ShowHideCursor) {
MotermModel model(MotermModel::Size(43, 132), MotermModel::Size(25, 80),
nullptr);
// The cursor should start visible.
EXPECT_TRUE(model.GetCursorVisibility());
MotermModel::StateChanges state_changes;
// Note: A lot of sources on the web have show/hide backwards!
static const char kHideCursor[] = "\x1b[?25l";
model.ProcessInput(kHideCursor, sizeof(kHideCursor) - 1, &state_changes);
EXPECT_TRUE(state_changes.IsDirty());
EXPECT_TRUE(state_changes.cursor_changed);
EXPECT_FALSE(model.GetCursorVisibility());
state_changes.Reset();
static const char kShowCursor[] = "\x1b[?25h";
model.ProcessInput(kShowCursor, sizeof(kShowCursor) - 1, &state_changes);
EXPECT_TRUE(state_changes.IsDirty());
EXPECT_TRUE(state_changes.cursor_changed);
EXPECT_TRUE(model.GetCursorVisibility());
}
class SetResetKeypadModeTestDelegate : public MotermModel::Delegate {
public:
SetResetKeypadModeTestDelegate() {}
~SetResetKeypadModeTestDelegate() override {}
void OnResponse(const void* buf, size_t size) override { CHECK(false); }
void OnSetKeypadMode(bool application_mode) override {
call_count_++;
last_application_mode_ = application_mode;
}
int call_count() const { return call_count_; }
bool last_application_mode() const { return last_application_mode_; }
private:
int call_count_ = 0;
bool last_application_mode_ = false;
};
TEST(MotermModelTest, SetResetKeypadMode) {
SetResetKeypadModeTestDelegate test_delegate;
MotermModel model(MotermModel::Size(43, 132), MotermModel::Size(25, 80),
&test_delegate);
ASSERT_EQ(0, test_delegate.call_count());
ASSERT_FALSE(test_delegate.last_application_mode());
MotermModel::StateChanges state_changes;
static const char kSetKeypadAppMode[] = "\x1b=";
model.ProcessInput(kSetKeypadAppMode, sizeof(kSetKeypadAppMode) - 1,
&state_changes);
EXPECT_FALSE(state_changes.IsDirty());
EXPECT_EQ(1, test_delegate.call_count());
EXPECT_TRUE(test_delegate.last_application_mode());
state_changes.Reset();
static const char kResetKeypadAppMode[] = "\x1b>";
model.ProcessInput(kResetKeypadAppMode, sizeof(kResetKeypadAppMode) - 1,
&state_changes);
EXPECT_FALSE(state_changes.IsDirty());
EXPECT_EQ(2, test_delegate.call_count());
EXPECT_FALSE(test_delegate.last_application_mode());
};
// TODO(vtl): Test responses.
} // namespace