blob: 328b6b5c5feeb725e14e9dc5f8f661108cafca93 [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 "wrapped_test_case_step.h"
#include <memory>
#include <utility>
#include <base/check.h>
#include <chromeos/libipp/ipp.h>
#include <chromeos/libipp/ipp_operations.h>
#include <gmock/gmock.h>
#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include "parse_textproto.h"
#include "mock_printer/proto/control_flow.pb.h"
#include "mock_printer/proto/ipp.pb.h"
#include "wrapped_matcher.h"
// This file provides unit tests for `WrappedTestCaseStep`. Testing
// is performed by
// * using custom (invalid, illegal-in-production) messages that hide
// individual numeric markers inside the `ipp::Request`s and
// `mocking::IppMessage`s and
// * injecting a `WrappedMatcher` that knows how to find and correlate
// the markers.
//
// The convention adopted in this unit test is to hide the tell-tale
// numeric markers
// * in the `job_id` of the `ipp::Request`,
// * in the `version_number` of the `mocking::IppMessage`, and
// * in the `pause_seconds` of the `mocking::Response`.
namespace mock_printer {
namespace {
using ::testing::IsNull;
using ::testing::NotNull;
// Convenience function that builds test data.
std::unique_ptr<ipp::Request> MakeRequest(int value) {
auto request = std::make_unique<ipp::Request_Get_Job_Attributes>();
request->operation_attributes->job_id.Set(value);
return request;
}
// Defines a custom `WrappedMatcher` that doesn't rely on the actual
// semantics of IPP matching.
class FakeWrappedMatcher : public WrappedMatcher {
public:
static std::unique_ptr<WrappedMatcher> Create() {
return std::make_unique<FakeWrappedMatcher>();
}
FakeWrappedMatcher() = default;
~FakeWrappedMatcher() override = default;
// See the file-level comment about the tell-tale numeric markers.
bool Match(const MatchableData data) override {
auto* ipp_data = std::get_if<MatchableIppData>(&data);
CHECK(ipp_data) << "BUG: expected `MatchableIppData` variant";
int job_id = 0;
// const_cast needed because `TCollection* operator->()` is not
// marked const.
auto* request = const_cast<ipp::Request_Get_Job_Attributes*>(
dynamic_cast<const ipp::Request_Get_Job_Attributes*>(
ipp_data->ipp_request));
CHECK(request->operation_attributes->job_id.GetValue(&job_id))
<< "BUG: failed to get job_id";
return job_id == ipp_data->mock_ipp_request.version_number();
}
};
// Tests that a trivial test case step with exactly one expectation
// succeeds.
TEST(WrappedTestCaseStep, SingleExpectationSuccess) {
const auto test_case = ParseTestCaseOrDie(R"pb(
steps {
cardinality { type: ALL_IN_ORDER }
expectation_with_response {
expectation { ipp_matcher { version_number: 1138 } }
response { pause_seconds: 1139 }
}
}
)pb");
auto matcher = FakeWrappedMatcher::Create();
auto step = WrappedTestCaseStep::Create(test_case.steps(0), matcher.get());
auto request = MakeRequest(1138);
InputMessage input(request.get());
ProgressionResult result = step->Progress(input);
EXPECT_TRUE(result.match_found);
EXPECT_EQ(result.step_status, StepStatus::kSaturated);
ASSERT_THAT(result.response, NotNull());
EXPECT_EQ(result.response->pause_seconds(), 1139);
}
// Tests the case where an `InputMessage` matches nothing in the
// particular `WrappedTestCaseStep`.
TEST(WrappedTestCaseStep, NoMatchingExpectation) {
const auto test_case = ParseTestCaseOrDie(R"pb(
steps {
cardinality { type: ALL_IN_ORDER }
expectation_with_response {
expectation { ipp_matcher { version_number: 1138 } }
response { pause_seconds: 1139 }
}
}
)pb");
auto matcher = FakeWrappedMatcher::Create();
auto step = WrappedTestCaseStep::Create(test_case.steps(0), matcher.get());
// 0 != 1138; the matcher will not correlate this with the given
// expectation.
auto request = MakeRequest(0);
InputMessage input(request.get());
ProgressionResult result = step->Progress(input);
EXPECT_FALSE(result.match_found);
EXPECT_EQ(result.step_status, StepStatus::kUnfulfilled);
EXPECT_THAT(result.response, IsNull());
}
// Tests that a test case step with multiple expectations succeeds.
TEST(WrappedTestCaseStep, MultiExpectationSuccess) {
const auto test_case = ParseTestCaseOrDie(R"pb(
steps {
cardinality { type: ALL_IN_ANY_ORDER }
expectation_with_response {
expectation { ipp_matcher { version_number: 1138 } }
response { pause_seconds: 1139 }
}
expectation_with_response {
expectation { ipp_matcher { version_number: 2038 } }
response { pause_seconds: 2039 }
}
expectation_with_response {
expectation { ipp_matcher { version_number: 3038 } }
response { pause_seconds: 3039 }
}
}
)pb");
auto matcher = FakeWrappedMatcher::Create();
auto step = WrappedTestCaseStep::Create(test_case.steps(0), matcher.get());
// Progress the step by hitting the third ExpectationWithResponse.
auto first_request = MakeRequest(3038);
InputMessage first_input(first_request.get());
ProgressionResult first_result = step->Progress(first_input);
EXPECT_TRUE(first_result.match_found);
EXPECT_EQ(first_result.step_status, StepStatus::kUnfulfilled);
ASSERT_THAT(first_result.response, NotNull());
EXPECT_EQ(first_result.response->pause_seconds(), 3039);
// Progress the step by hitting the second ExpectationWithResponse.
auto second_request = MakeRequest(2038);
InputMessage second_input(second_request.get());
ProgressionResult second_result = step->Progress(second_input);
EXPECT_TRUE(second_result.match_found);
EXPECT_EQ(second_result.step_status, StepStatus::kUnfulfilled);
ASSERT_THAT(second_result.response, NotNull());
EXPECT_EQ(second_result.response->pause_seconds(), 2039);
// Progress and saturate the step by hitting the first
// ExpectationWithResponse.
auto third_request = MakeRequest(1138);
InputMessage third_input(third_request.get());
ProgressionResult third_result = step->Progress(third_input);
EXPECT_TRUE(third_result.match_found);
EXPECT_EQ(third_result.step_status, StepStatus::kSaturated);
ASSERT_THAT(third_result.response, NotNull());
EXPECT_EQ(third_result.response->pause_seconds(), 1139);
}
// Tests that a test case step can fulfill without saturating.
TEST(WrappedTestCaseStep, FulfillWithoutSaturating) {
const auto test_case = ParseTestCaseOrDie(R"pb(
steps {
cardinality {
type: SOME_OF
count: { at_least: 2 }
}
expectation_with_response {
expectation { ipp_matcher { version_number: 1138 } }
response { pause_seconds: 1139 }
}
expectation_with_response {
expectation { ipp_matcher { version_number: 2038 } }
response { pause_seconds: 2039 }
}
expectation_with_response {
expectation { ipp_matcher { version_number: 3038 } }
response { pause_seconds: 3039 }
}
}
)pb");
auto matcher = FakeWrappedMatcher::Create();
auto step = WrappedTestCaseStep::Create(test_case.steps(0), matcher.get());
// Progress the step by hitting the third ExpectationWithResponse.
auto first_request = MakeRequest(3038);
InputMessage first_input(first_request.get());
ProgressionResult first_result = step->Progress(first_input);
EXPECT_TRUE(first_result.match_found);
EXPECT_EQ(first_result.step_status, StepStatus::kUnfulfilled);
ASSERT_THAT(first_result.response, NotNull());
EXPECT_EQ(first_result.response->pause_seconds(), 3039);
// Progress the step by hitting the second ExpectationWithResponse.
// This will fulfill the step without saturating it.
auto second_request = MakeRequest(2038);
InputMessage second_input(second_request.get());
ProgressionResult second_result = step->Progress(second_input);
EXPECT_TRUE(second_result.match_found);
EXPECT_EQ(second_result.step_status, StepStatus::kFulfilled);
ASSERT_THAT(second_result.response, NotNull());
EXPECT_EQ(second_result.response->pause_seconds(), 2039);
// Make no progress in the step by comparing against a non-matching
// input message.
auto third_request = MakeRequest(0);
InputMessage third_input(third_request.get());
ProgressionResult third_result = step->Progress(third_input);
EXPECT_FALSE(third_result.match_found);
EXPECT_EQ(third_result.step_status, StepStatus::kFulfilled);
ASSERT_THAT(third_result.response, IsNull());
}
} // namespace
} // namespace mock_printer