// Copyright (C) 2025 wangyusong
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package test

// Case is a BDD style test case for a feature.
//
// Background: https://en.wikipedia.org/wiki/Behavior-driven_development.
// Aha, maybe you don't need to fully understand it,
// we just use Scenario, Given, When, Then to describe a test case, which has several advantages:
//  1. Highly readable and easy to maintain.
//  2. It can be used as a requirement or use case description, helping you in the TDD process,
//     let AI generate code, that is "code as prompt".
//  3. Test against requirement descriptions, not implementation details.
//     Top-down, and the requirement level is above the details.
//
// To add, "requirement" here is a broad concept, not or not only refers to the requirements
// from the product side, but the interface behavior defined by the test module.
//
// TODO: Use this consistently.
type Case[T1 any, T2 any, T3 any] struct {
	// Scenario describes feature of the test case.
	// E.g. "Query hot block with label filters".
	Scenario string

	// Given is initial "context"!!!(context != parameters of method)
	// at the beginning of the scenario, in one or more clauses.
	// E.g. "a hot block with indexed feeds".
	Given string
	// When is the event that triggers the scenario.
	// E.g. "querying with label filters".
	When string
	// Then is the expected outcome, in one or more clauses.
	// E.g. "should return matching feeds".
	Then string

	// GivenDetail is the detail of the given context.
	// Generally speaking, it describes what "state the object" of the module should have.
	// E.g. 'hot block', what does it look like, what are its member variable values?
	// What is the expected behavior of external dependencies?
	GivenDetail T1
	// WhenDetail is the detail of the when event.
	// Generally speaking, it describes the "parameters of the method call".
	// E.g. what does the query options look like.
	WhenDetail T2
	// ThenExpected is the expected outcome of the scenario.
	// Generally speaking, it describes the "return value of the method call".
	// E.g. what does the returned feeds look like.
	ThenExpected T3
}
