/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package policies_test

import (
	"testing"

	cb "github.com/hyperledger/fabric-protos-go/common"
	mb "github.com/hyperledger/fabric-protos-go/msp"
	"github.com/hyperledger/fabric/common/cauthdsl"
	"github.com/hyperledger/fabric/common/policies"
	"github.com/hyperledger/fabric/common/policydsl"
	"github.com/hyperledger/fabric/msp"
	"github.com/hyperledger/fabric/protoutil"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/require"
)

func TestImplicitMetaPolicy_Convert(t *testing.T) {

	// Scenario: we attempt the conversion of a simple metapolicy requiring
	// ALL of 2 sub-policies, each of which are plain signedby

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	})
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p2)
	require.NoError(t, err)

	p := &policies.PolicyLogger{
		Policy: &policies.ImplicitMetaPolicy{
			Threshold:     2,
			SubPolicyName: "mypolicy",
			SubPolicies:   []policies.Policy{p1, p2},
		},
	}

	spe, err := p.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.SignedBy(0),
			policydsl.SignedBy(1),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	}, spe)
}

func TestImplicitMetaPolicy_Convert1(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy requiring
	// ALL of 2 sub-policies, where the first one is an OR of 2 and
	// the second one is an OR of 1, with a principal that is already
	// referenced by the first

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(policydsl.SignedByAnyMember([]string{"A", "B"}))
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(policydsl.SignedByAnyMember([]string{"B"}))
	require.NotNil(t, p2)
	require.NoError(t, err)

	p := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{p1, p2},
	}

	spe, err := p.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.Or(
				policydsl.SignedBy(0),
				policydsl.SignedBy(1),
			),
			policydsl.NOutOf(1,
				[]*cb.SignaturePolicy{policydsl.SignedBy(1)},
			),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	}, spe)
}

func TestImplicitMetaPolicy_Convert2(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy requiring
	// ALL of 2 sub-policies, where the first one is an OR of an AND
	// of 2 and an OR of 1 and the second one is an AND of 2, with
	// principal deduplication required

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.NOutOf(1,
			[]*cb.SignaturePolicy{
				policydsl.NOutOf(2,
					[]*cb.SignaturePolicy{
						policydsl.SignedBy(0),
						policydsl.SignedBy(1),
					},
				),
				policydsl.NOutOf(1,
					[]*cb.SignaturePolicy{
						policydsl.SignedBy(2),
					},
				),
			},
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "D",
					},
				),
			},
		},
	})
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.NOutOf(2,
			[]*cb.SignaturePolicy{
				policydsl.SignedBy(0),
				policydsl.SignedBy(1),
			},
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p2)
	require.NoError(t, err)

	p := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{p1, p2},
	}

	spe, err := p.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.NOutOf(1,
				[]*cb.SignaturePolicy{
					policydsl.NOutOf(2,
						[]*cb.SignaturePolicy{
							policydsl.SignedBy(0),
							policydsl.SignedBy(1),
						},
					),
					policydsl.NOutOf(1,
						[]*cb.SignaturePolicy{
							policydsl.SignedBy(2),
						},
					),
				},
			),
			policydsl.NOutOf(2,
				[]*cb.SignaturePolicy{
					policydsl.SignedBy(3),
					policydsl.SignedBy(0),
				},
			),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "D",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	}, spe)
}

func TestImplicitMetaPolicy_Convert3(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy requiring
	// ALL of 2 sub-policies, where the first one is a metapolicy itself,
	// requiring ALL of 2 simple subpolicies to be satisfied and the
	// second is a simple subpolicy, with no principal deduplication

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	})
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p2)
	require.NoError(t, err)

	p3, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
		},
	})
	require.NotNil(t, p3)
	require.NoError(t, err)

	mp1 := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{p1, p2},
	}

	mp2 := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{mp1, p3},
	}

	spe, err := mp2.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.And(
				policydsl.SignedBy(0),
				policydsl.SignedBy(1),
			),
			policydsl.SignedBy(2),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
		},
	}, spe)
}

func TestImplicitMetaPolicy_Convert4(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy requiring
	// ALL of 2 sub-policies, where the first one is a metapolicy itself,
	// requiring ALL of 2 simple subpolicies to be satisfied and the
	// second is a simple subpolicy, with principal deduplication

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	})
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	})
	require.NotNil(t, p2)
	require.NoError(t, err)

	p3, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule:    policydsl.SignedBy(0),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	})
	require.NotNil(t, p3)
	require.NoError(t, err)

	mp1 := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{p1, p2},
	}

	mp2 := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{mp1, p3},
	}

	spe, err := mp2.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.And(
				policydsl.SignedBy(0),
				policydsl.SignedBy(0),
			),
			policydsl.SignedBy(0),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	}, spe)
}

func TestImplicitMetaPolicy_Convert5(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy requiring
	// ALL of 2 sub-policies, where the first one is an OR of an AND
	// of 2 and an OR of 1 and the second one is an AND of 2, with
	// principal deduplication required both across the two subpolicies
	// and within the first

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.NOutOf(1,
			[]*cb.SignaturePolicy{
				policydsl.NOutOf(2,
					[]*cb.SignaturePolicy{
						policydsl.SignedBy(0),
						policydsl.SignedBy(1),
					},
				),
				policydsl.NOutOf(1,
					[]*cb.SignaturePolicy{
						policydsl.SignedBy(2),
					},
				),
			},
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.NOutOf(2,
			[]*cb.SignaturePolicy{
				policydsl.SignedBy(0),
				policydsl.SignedBy(1),
			},
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p2)
	require.NoError(t, err)

	p := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{p1, p2},
	}

	spe, err := p.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.NOutOf(1,
				[]*cb.SignaturePolicy{
					policydsl.NOutOf(2,
						[]*cb.SignaturePolicy{
							policydsl.SignedBy(0),
							policydsl.SignedBy(1),
						},
					),
					policydsl.NOutOf(1,
						[]*cb.SignaturePolicy{
							policydsl.SignedBy(0),
						},
					),
				},
			),
			policydsl.NOutOf(2,
				[]*cb.SignaturePolicy{
					policydsl.SignedBy(2),
					policydsl.SignedBy(0),
				},
			),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "A",
					},
				),
			},
		},
	}, spe)
}

func TestImplicitMetaPolicy_Convert6(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy requiring
	// ALL of 2 sub-policies, where the first one is an OR of an AND
	// of 2 and an OR of 1 and the second one is an AND of 2, with
	// principal deduplication required both across the two subpolicies
	// and within the first and the second

	pfs := &cauthdsl.EnvelopeBasedPolicyProvider{}

	p1, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.NOutOf(1,
			[]*cb.SignaturePolicy{
				policydsl.NOutOf(2,
					[]*cb.SignaturePolicy{
						policydsl.SignedBy(0),
						policydsl.SignedBy(1),
					},
				),
				policydsl.NOutOf(1,
					[]*cb.SignaturePolicy{
						policydsl.SignedBy(2),
					},
				),
			},
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p1)
	require.NoError(t, err)

	p2, err := pfs.NewPolicy(&cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.NOutOf(2,
			[]*cb.SignaturePolicy{
				policydsl.SignedBy(0),
				policydsl.SignedBy(1),
			},
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
		},
	})
	require.NotNil(t, p2)
	require.NoError(t, err)

	p := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{p1, p2},
	}

	spe, err := p.Convert()
	require.NoError(t, err)
	require.NotNil(t, spe)
	require.Equal(t, &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: policydsl.And(
			policydsl.NOutOf(1,
				[]*cb.SignaturePolicy{
					policydsl.NOutOf(2,
						[]*cb.SignaturePolicy{
							policydsl.SignedBy(0),
							policydsl.SignedBy(1),
						},
					),
					policydsl.NOutOf(1,
						[]*cb.SignaturePolicy{
							policydsl.SignedBy(0),
						},
					),
				},
			),
			policydsl.NOutOf(2,
				[]*cb.SignaturePolicy{
					policydsl.SignedBy(0),
					policydsl.SignedBy(0),
				},
			),
		),
		Identities: []*mb.MSPPrincipal{
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "B",
					},
				),
			},
			{
				PrincipalClassification: mb.MSPPrincipal_ROLE,
				Principal: protoutil.MarshalOrPanic(
					&mb.MSPRole{
						Role:          mb.MSPRole_MEMBER,
						MspIdentifier: "C",
					},
				),
			},
		},
	}, spe)
}

type inconvertiblePolicy struct{}

func (i *inconvertiblePolicy) EvaluateSignedData(signatureSet []*protoutil.SignedData) error {
	return nil
}

func (i *inconvertiblePolicy) EvaluateIdentities(signatureSet []msp.Identity) error {
	return nil
}

func TestImplicitMetaPolicy_Convert7(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy
	// with an incovertible subpolicy

	p := &policies.ImplicitMetaPolicy{
		Threshold:     2,
		SubPolicyName: "mypolicy",
		SubPolicies:   []policies.Policy{&inconvertiblePolicy{}},
	}

	spe, err := p.Convert()
	require.EqualError(t, err, "subpolicy number 0 type *policies_test.inconvertiblePolicy of policy mypolicy is not convertible")
	require.Nil(t, spe)
}

type convertFailurePolicy struct{}

func (i *convertFailurePolicy) EvaluateSignedData(signatureSet []*protoutil.SignedData) error {
	return nil
}

func (i *convertFailurePolicy) EvaluateIdentities(identities []msp.Identity) error {
	return nil
}

func (i *convertFailurePolicy) Convert() (*cb.SignaturePolicyEnvelope, error) {
	return nil, errors.New("nope")
}

func TestImplicitMetaPolicy_Convert8(t *testing.T) {

	// Scenario: we attempt the conversion of a metapolicy
	// with a subpolicy whose conversion fails

	p := &policies.PolicyLogger{
		Policy: &policies.ImplicitMetaPolicy{
			Threshold:     2,
			SubPolicyName: "mypolicy",
			SubPolicies:   []policies.Policy{&convertFailurePolicy{}},
		},
	}

	spe, err := p.Convert()
	require.EqualError(t, err, "failed to convert subpolicy number 0 of policy mypolicy: nope")
	require.Nil(t, spe)
}
