void test_willRenderFeature_symbolsForFeature()
    {
      // prepare features
      QgsVectorLayer* layer = new QgsVectorLayer( "point?field=fld:int", "x", "memory" );
      int idx = layer->fieldNameIndex( "fld" );
      QVERIFY( idx != -1 );
      QgsFeature f1;
      f1.initAttributes( 1 );
      f1.setAttribute( idx, QVariant( 2 ) );
      QgsFeature f2;
      f2.initAttributes( 1 );
      f2.setAttribute( idx, QVariant( 8 ) );
      QgsFeature f3;
      f3.initAttributes( 1 );
      f3.setAttribute( idx, QVariant( 100 ) );

      // prepare renderer
      QgsSymbol* s1 = QgsSymbol::defaultSymbol( QgsWkbTypes::PointGeometry );
      QgsSymbol* s2 = QgsSymbol::defaultSymbol( QgsWkbTypes::PointGeometry );
      RRule* rootRule = new RRule( nullptr );
      rootRule->appendChild( new RRule( s1, 0, 0, "fld >= 5 and fld <= 20" ) );
      rootRule->appendChild( new RRule( s2, 0, 0, "fld <= 10" ) );
      QgsRuleBasedRenderer r( rootRule );

      QVERIFY( r.capabilities() & QgsFeatureRenderer::MoreSymbolsPerFeature );

      QgsRenderContext ctx; // dummy render context
      ctx.expressionContext().setFields( layer->fields() );
      r.startRender( ctx, layer->fields() );

      // test willRenderFeature
      ctx.expressionContext().setFeature( f1 );
      QVERIFY( r.willRenderFeature( f1, ctx ) );
      ctx.expressionContext().setFeature( f2 );
      QVERIFY( r.willRenderFeature( f2, ctx ) );
      ctx.expressionContext().setFeature( f3 );
      QVERIFY( !r.willRenderFeature( f3, ctx ) );

      // test symbolsForFeature
      ctx.expressionContext().setFeature( f1 );
      QgsSymbolList lst1 = r.symbolsForFeature( f1, ctx );
      QVERIFY( lst1.count() == 1 );
      ctx.expressionContext().setFeature( f2 );
      QgsSymbolList lst2 = r.symbolsForFeature( f2, ctx );
      QVERIFY( lst2.count() == 2 );
      ctx.expressionContext().setFeature( f3 );
      QgsSymbolList lst3 = r.symbolsForFeature( f3, ctx );
      QVERIFY( lst3.isEmpty() );

      r.stopRender( ctx );

      delete layer;
    }
    void test_willRenderFeature_symbolsForFeature()
    {
      // prepare features
      QgsVectorLayer* layer = new QgsVectorLayer( "point?field=fld:int", "x", "memory" );
      int idx = layer->fieldNameIndex( "fld" );
      QVERIFY( idx != -1 );
      QgsFeature f1; f1.initAttributes( 1 ); f1.setAttribute( idx, QVariant( 2 ) );
      QgsFeature f2; f2.initAttributes( 1 ); f2.setAttribute( idx, QVariant( 8 ) );
      QgsFeature f3; f3.initAttributes( 1 ); f3.setAttribute( idx, QVariant( 100 ) );

      // prepare renderer
      QgsSymbolV2* s1 = QgsSymbolV2::defaultSymbol( QGis::Point );
      QgsSymbolV2* s2 = QgsSymbolV2::defaultSymbol( QGis::Point );
      RRule* rootRule = new RRule( NULL );
      rootRule->appendChild( new RRule( s1, 0, 0, "fld >= 5 and fld <= 20" ) );
      rootRule->appendChild( new RRule( s2, 0, 0, "fld <= 10" ) );
      QgsRuleBasedRendererV2 r( rootRule );

      QVERIFY( r.capabilities() & QgsFeatureRendererV2::MoreSymbolsPerFeature );

      QgsRenderContext ctx; // dummy render context
      r.startRender( ctx, layer->pendingFields() );

      // test willRenderFeature
      QVERIFY( r.willRenderFeature( f1 ) );
      QVERIFY( r.willRenderFeature( f2 ) );
      QVERIFY( !r.willRenderFeature( f3 ) );

      // test symbolsForFeature
      QgsSymbolV2List lst1 = r.symbolsForFeature( f1 );
      QVERIFY( lst1.count() == 1 );
      QgsSymbolV2List lst2 = r.symbolsForFeature( f2 );
      QVERIFY( lst2.count() == 2 );
      QgsSymbolV2List lst3 = r.symbolsForFeature( f3 );
      QVERIFY( lst3.count() == 0 );

      r.stopRender( ctx );

      delete layer;
    }
    void test_clone_ruleKey()
    {
      RRule* rootRule = new RRule( 0 );
      RRule* sub1Rule = new RRule( 0, 0, 0, "fld > 1" );
      RRule* sub2Rule = new RRule( 0, 0, 0, "fld > 2" );
      RRule* sub3Rule = new RRule( 0, 0, 0, "fld > 3" );
      rootRule->appendChild( sub1Rule );
      sub1Rule->appendChild( sub2Rule );
      sub2Rule->appendChild( sub3Rule );
      QgsRuleBasedRenderer r( rootRule );

      QgsRuleBasedRenderer* clone = static_cast<QgsRuleBasedRenderer*>( r.clone() );
      RRule* cloneRootRule = clone->rootRule();
      RRule* cloneSub1Rule = cloneRootRule->children()[0];
      RRule* cloneSub2Rule = cloneSub1Rule->children()[0];
      RRule* cloneSub3Rule = cloneSub2Rule->children()[0];

      QCOMPARE( rootRule->ruleKey(), cloneRootRule->ruleKey() );
      QCOMPARE( sub1Rule->ruleKey(), cloneSub1Rule->ruleKey() );
      QCOMPARE( sub2Rule->ruleKey(), cloneSub2Rule->ruleKey() );
      QCOMPARE( sub3Rule->ruleKey(), cloneSub3Rule->ruleKey() );

      delete clone;
    }