Repository: paritytech/substrate
File: primitives/npos-elections/src/tests.rs (Rust)

Code before:
//! Tests for npos-elections.

use crate::{
	balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map,
	Assignment, BalancingConfig, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter,
};
use sp_arithmetic::{PerU16, Perbill, Percent, Permill};
use substrate_test_utils::assert_eq_uvec;

#[test]
fn float_phragmen_poc_works() {
	let candidates = vec![1, 2, 3];
	let voters = vec![(10, vec![1, 2]), (20, vec![1, 3]), (30, vec![2, 3])];
	let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30), (1, 0), (2, 0), (3, 0)]);
	let mut phragmen_result = elect_float(2, candidates, voters, &stake_of).unwrap();
	let winners = phragmen_result.clone().winners;
	let assignments = phragmen_result.clone().assignments;

	assert_eq_uvec!(winners, vec![(2, 40), (3, 50)]);
	assert_eq_uvec!(
		assignments,
		vec![(10, vec![(2, 1.0)]), (20, vec![(3, 1.0)]), (30, vec![(2, 0.5), (3, 0.5)]),]
	);

	let mut support_map = build_support_map_float(&mut phragmen_result, &stake_of);

	assert_eq!(
		support_map.get(&2).unwrap(),
		&_Support { own: 0.0, total: 25.0, others: vec![(10u64, 10.0), (30u64, 15.0)] }
	);
	assert_eq!(
		support_map.get(&3).unwrap(),
		&_Support { own: 0.0, total: 35.0, others: vec![(20u64, 20.0), (30u64, 15.0)] }
	);

	equalize_float(phragmen_result.assignments, &mut support_map, 0.0, 2, stake_of);

	assert_eq!(
		support_map.get(&2).unwrap(),
		&_Support { own: 0.0, total: 30.0, others: vec![(10u64, 10.0), (30u64, 20.0)] }
	);
	assert_eq!(
		support_map.get(&3).unwrap(),
		&_Support { own: 0.0, total: 30.0, others: vec![(20u64, 20.0), (30u64, 10.0)] }
	);
}

#[test]
fn phragmen_core_test_without_edges() {
	let candidates = vec![1, 2, 3];
	let voters = vec![(10, 10, vec![]), (20, 20, vec![]), (30, 30, vec![])];

Review comment (suggestion):
@kianenigma I want to bring one thing up to make sure we're on the same page. The approval voting is not normalising the vote weights, as you can see in the test vecs below. i.e. each assignment's vote distribution is 100%, regardless of the number of candidates backed by each voter. The reasoning behind this is that each vote should be backed with 100% weight of the voter's stake for all voted candidates.

The caller can still normalise the votes after calling `fn approval_voting`, as it is demonstrated by these tests in the [election-provider-support](https://github.com/paritytech/substrate/blob/f4a0f341b7eb7973f183504743f7f76ad219c002/frame/election-provider-support/src/onchain.rs#L353).

This is the behaviour I expect form an approval voting scheme and added a [comment about it](https://github.com/paritytech/substrate/blob/f4a0f341b7eb7973f183504743f7f76ad219c002/primitives/npos-elections/src/approval_voting.rs#L30).



Code after:
//! Tests for npos-elections.

use crate::{
	approval_voting::*, balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core,
	setup_inputs, to_support_map, Assignment, BalancingConfig, ElectionResult, ExtendedBalance,
	StakedAssignment, Support, Voter,
};
use sp_arithmetic::{PerU16, Perbill, Percent, Permill};
use substrate_test_utils::assert_eq_uvec;

#[test]
fn approval_voting_works() {
	let candidates = vec![1, 2, 3, 4];
	let voters = vec![(10, vec![1, 2]), (20, vec![1, 2]), (30, vec![1, 2, 3]), (40, vec![4])];
	let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30), (40, 40)]);

	let voters = voters
		.iter()
		.map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone()))
		.collect::<Vec<_>>();

	let ElectionResult::<_, Perbill> { winners, assignments } =
		approval_voting(3, candidates, voters).unwrap();

	assert_eq_uvec!(winners, vec![(1, 60), (2, 60), (4, 40)]);
	assert_eq_uvec!(
		assignments,
		vec![
			Assignment {
				who: 10u64,
				distribution: vec![
					(1, Perbill::from_percent(100)),
					(2, Perbill::from_percent(100))
				]
			},
			Assignment {
				who: 20u64,
				distribution: vec![
					(1, Perbill::from_percent(100)),
					(2, Perbill::from_percent(100))
				]
			},
			Assignment {
				who: 30u64,
				distribution: vec![
					(1, Perbill::from_percent(100)),
					(2, Perbill::from_percent(100))
				]
			},
			Assignment { who: 40u64, distribution: vec![(4, Perbill::from_percent(100))] },
		]