private static FilterSpecPlanPathForge FindPath(
            SupportFilterPlanPath pathExpected,
            IList<FilterSpecPlanPathForge> pathsReceived)
        {
            var tripletsExpected = SortTriplets(pathExpected.Triplets);
            FilterSpecPlanPathForge found = null;

            foreach (var pathReceived in pathsReceived) {
                if (pathExpected.Triplets.Length != pathReceived.Triplets.Length) {
                    continue;
                }

                var tripletsReceived = SortTriplets(pathReceived.Triplets);
                var matches = true;
                for (var i = 0; i < tripletsReceived.Length; i++) {
                    var expected = tripletsExpected[i];
                    var received = tripletsReceived[i];
                    if (!expected.Lookupable.Equals(received.Param.Lookupable.Expression) ||
                        !expected.Op.Equals(received.Param.FilterOperator)) {
                        matches = false;
                        break;
                    }

                    var builder = new StringBuilder();
                    received.Param.ValueExprToString(builder, 0);
                    var value = builder.ToString();
                    if (expected.Op == EQUAL) {
                        var textExpected = FilterSpecParamConstantForge.ValueExprToString(expected.Value);
                        if (!textExpected.Equals(value)) {
                            matches = false;
                            break;
                        }
                    }
                    else if (expected.Op == BOOLEAN_EXPRESSION || expected.Op == REBOOL) {
                        var textExpected = FilterSpecParamExprNodeForge.ValueExprToString(expected.Value);
                        if (!textExpected.Equals(value)) {
                            matches = false;
                            break;
                        }
                    }
                    else {
                        throw new IllegalStateException("Filter op " + expected.Op + " not handled");
                    }
                }

                if (matches) {
                    if (found != null) {
                        throw new IllegalStateException("Multiple matches");
                    }

                    found = pathReceived;
                }
            }

            return found;
        }
 private static void AssertPlanPathTriplet(
     SupportFilterPlanTriplet tripletExpected,
     FilterSpecPlanPathTripletForge tripletReceived)
 {
     AssertExpressionOpt(tripletExpected.ControlConfirm, tripletReceived.TripletConfirm);
     Assert.AreEqual(tripletExpected.Lookupable, tripletReceived.Param.Lookupable.Expression);
     Assert.AreEqual(tripletExpected.Op, tripletReceived.Param.FilterOperator);
     var @out = new StringBuilder();
     tripletReceived.Param.ValueExprToString(@out, 0);
     if (tripletExpected.Op == EQUAL) {
         var expected = FilterSpecParamConstantForge.ValueExprToString(tripletExpected.Value);
         Assert.AreEqual(expected, @out.ToString());
     }
     else if (tripletExpected.Op == BOOLEAN_EXPRESSION || tripletExpected.Op == REBOOL) {
         var expected = FilterSpecParamExprNodeForge.ValueExprToString(tripletExpected.Value);
         Assert.AreEqual(expected, @out.ToString());
     }
     else {
         Assert.Fail("operator value to-string not supported yet");
     }
 }