<commit_before>/*
 *  ____    ____    _____    ____    ___     ____ 
 * |  _ \  |  _ \  | ____|  / ___|  / _/    / ___|        Precog (R)
 * | |_) | | |_) | |  _|   | |     | |  /| | |  _         Advanced Analytics Engine for NoSQL Data
 * |  __/  |  _ <  | |___  | |___  |/ _| | | |_| |        Copyright (C) 2010 - 2013 SlamData, Inc.
 * |_|     |_| \_\ |_____|  \____|   /__/   \____|        All Rights Reserved.
 *
 * 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 <http://www.gnu.org/licenses/>.
 *
 */
package com.precog.quirrel
package emitter

import com.precog.bytecode.Instructions
import com.precog.bytecode.RandomLibrary

import org.scalacheck.Prop
import org.specs2.ScalaCheck
import org.specs2.mutable._

import java.io.File
import scala.io.Source
import com.codecommit.gll.LineStream

import typer._

object GroupSolverSpecs extends Specification
    with ScalaCheck
    with StubPhases
    with Compiler
    with GroupSolver
    with ProvenanceChecker
    with RawErrors 
    with RandomLibrary {
      
  import ast._
  import buckets._
      
  "group solver" should {
    "identify and solve group set for trivial solve example" in {
      val input = "clicks := load(//clicks) solve 'day clicks where clicks.day = 'day"
      
      val Let(_, _, _, _,
        tree @ Solve(_, _, 
          origin @ Where(_, target, pred @ Eq(_, solution, _)))) = compile(input)
          
      val expected = Group(Some(origin), target, UnfixedSolution("'day", solution))
      tree.errors must beEmpty
      tree.buckets must beSome(expected)
    }
    
    "identify composite bucket for trivial solve example with conjunction" in {
      val input = "clicks := load(//clicks) solve 'day clicks where clicks.day = 'day & clicks.din = 'day"
      
      val Let(_, _, _, _,
        tree @ Solve(_, _, 
          origin @ Where(_, target, And(_, Eq(_, leftSol, _), Eq(_, rightSol, _))))) = compile(input)
      
      val expected = Group(Some(origin), target,
        IntersectBucketSpec(
          UnfixedSolution("'day", leftSol),
          UnfixedSolution("'day", rightSol)))
      
      tree.errors must beEmpty
      tree.buckets must beSome(expected)
    }

    "identify and fail to solve problematic case of nested solves" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          solve 'weight
            medals where medals.Weight = 'weight & medals.Gender = 'gender
      """.stripMargin

      val Let(_, _, _, _,
        tree @ Solve(_, _, _)) = compile(input)

      tree.errors mustEqual Set(ConstraintsWithinInnerScope)
    }    

    "accept acceptable case of nested solves" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          medals' := medals where medals.Gender = 'gender

          solve 'weight
            medals' where medals'.Weight = 'weight
      """.stripMargin

      val let @ Let(_, _, _, _,
        tree1 @ Solve(_, _, 
          Let(_, _, _, _, 
            tree2 @ Solve(_, _, _)))) = compile(input)

      let.errors must beEmpty
      tree1.errors must beEmpty
      tree2.errors must beEmpty
    }    

    "accept acceptable case when a dispatch in one solve contains tic variable from another solve" in {
      val input = """
        medals := //summer_games/london_medals
        
        medals' := solve 'gender
          medals where medals.Gender = 'gender

        solve 'weight
          medals' where medals'.Weight = 'weight & medals'.isAwesome
      """.stripMargin

      val let @ Let(_, _, _, _,
        Let(_, _, _, _,
          tree @ Solve(_, _, _))) = compile(input)

      let.errors must beEmpty
      tree.errors must beEmpty
    }    

    "identify and fail to solve more complicated problematic case of nested solves" in {
      val input = """<commit_msg>Added test cases, including two broken ones.<commit_after>/*
 *  ____    ____    _____    ____    ___     ____ 
 * |  _ \  |  _ \  | ____|  / ___|  / _/    / ___|        Precog (R)
 * | |_) | | |_) | |  _|   | |     | |  /| | |  _         Advanced Analytics Engine for NoSQL Data
 * |  __/  |  _ <  | |___  | |___  |/ _| | | |_| |        Copyright (C) 2010 - 2013 SlamData, Inc.
 * |_|     |_| \_\ |_____|  \____|   /__/   \____|        All Rights Reserved.
 *
 * 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 <http://www.gnu.org/licenses/>.
 *
 */
package com.precog.quirrel
package emitter

import com.precog.bytecode.Instructions
import com.precog.bytecode.RandomLibrary

import org.scalacheck.Prop
import org.specs2.ScalaCheck
import org.specs2.mutable._

import java.io.File
import scala.io.Source
import com.codecommit.gll.LineStream

import typer._

object GroupSolverSpecs extends Specification
    with ScalaCheck
    with StubPhases
    with Compiler
    with GroupSolver
    with ProvenanceChecker
    with RawErrors 
    with RandomLibrary {
      
  import ast._
  import buckets._
      
  "group solver" should {
    "identify and solve group set for trivial solve example" in {
      val input = "clicks := load(//clicks) solve 'day clicks where clicks.day = 'day"
      
      val Let(_, _, _, _,
        tree @ Solve(_, _, 
          origin @ Where(_, target, pred @ Eq(_, solution, _)))) = compile(input)
          
      val expected = Group(Some(origin), target, UnfixedSolution("'day", solution))
      tree.errors must beEmpty
      tree.buckets must beSome(expected)
    }
    
    "identify composite bucket for trivial solve example with conjunction" in {
      val input = "clicks := load(//clicks) solve 'day clicks where clicks.day = 'day & clicks.din = 'day"
      
      val Let(_, _, _, _,
        tree @ Solve(_, _, 
          origin @ Where(_, target, And(_, Eq(_, leftSol, _), Eq(_, rightSol, _))))) = compile(input)
      
      val expected = Group(Some(origin), target,
        IntersectBucketSpec(
          UnfixedSolution("'day", leftSol),
          UnfixedSolution("'day", rightSol)))
      
      tree.errors must beEmpty
      tree.buckets must beSome(expected)
    }

    "identify and fail to solve problematic case of nested solves" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          solve 'weight
            medals where medals.Weight = 'weight & medals.Gender = 'gender
      """.stripMargin

      val Let(_, _, _, _,
        tree @ Solve(_, _, _)) = compile(input)

      tree.errors mustEqual Set(ConstraintsWithinInnerScope)
    }    

    "accept acceptable case of nested solves" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          medals' := medals where medals.Gender = 'gender

          solve 'weight
            medals' where medals'.Weight = 'weight
      """.stripMargin

      val let @ Let(_, _, _, _,
        tree1 @ Solve(_, _, 
          Let(_, _, _, _, 
            tree2 @ Solve(_, _, _)))) = compile(input)

      let.errors must beEmpty
      tree1.errors must beEmpty
      tree2.errors must beEmpty
    }    

    "accept acceptable case when one solve contains a dispatch which contains tic variable from another solve" in {
      val input = """
        medals := //summer_games/london_medals
        
        medals' := solve 'gender
          medals where medals.Gender = 'gender

        solve 'weight
          medals' where medals'.Weight = 'weight & medals'.isAwesome
      """.stripMargin

      val let @ Let(_, _, _, _,
        Let(_, _, _, _,
          tree @ Solve(_, _, _))) = compile(input)

      let.errors must beEmpty
      tree.errors must beEmpty
    } 

    "accept acceptable case when a dispatch in one solve contains, as an actual, a tic variable from another solve" in {
      val input = """
        medals := //summer_games/london_medals
        
        f(x) := x

        solve 'gender
          medals' := medals where medals.Gender = 'gender

          solve 'weight
            medals' where medals'.Weight = 'weight & f('gender)
      """.stripMargin

      val let @ Let(_, _, _, _,
        Let(_, _, _, _,
          tree @ Solve(_, _, _))) = compile(input)

      let.errors must beEmpty
      tree.errors must beEmpty
    } 

    "accept acceptable case when one solve contains a tic variable from another solve" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          medals' := medals where medals.Gender = 'gender

          solve 'weight
            medals' where medals'.Weight = 'weight & 'gender
      """.stripMargin

      val let @ Let(_, _, _, _,
          tree @ Solve(_, _, _)) = compile(input)

      let.errors must beEmpty
      tree.errors must beEmpty
    } 

    "accept a solve when the tic var is constrained in a let" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          gender := medals where medals.Gender = 'gender
          gender + 1
      """.stripMargin

      val tree @ Let(_, _, _, _,
        solve @ Solve(_, _, _)) = compile(input)

      solve.errors must beEmpty
      tree.errors must beEmpty
    }    

    "accept a solve when a tic var is used in the scope of a nested solve that doesn't bind it" in {
      val input = """
        medals := //summer_games/london_medals
        
        solve 'gender
          gender := medals where medals.Gender = 'gender
          
          solve 'weight
            weight := gender where gender.Weight = 'weight
            weight + 'gender
      """.stripMargin

      val tree @ Let(_, _, _, _,
        solve1 @ Solve(_, _,
          Let(_, _, _, _,
            solve2 @ Solve(_, _, _)))) = compile(input)

      solve1.errors must beEmpty
      solve2.errors must beEmpty
      tree.errors must beEmpty
    }    

    "identify and fail to solve more complicated problematic case of nested solves" in {
      val input = """
{'fraction_non_alphanumeric': 0.09981949458483755, 'fraction_numerical': 0.00315884476534296, 'mean_word_length': 2.125811001410437, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6347822', 'n_tokens_mistral': 3309, 'n_tokens_neox': 3123, 'n_words': 1005}