<commit_before>﻿module Barb.Tests.PredicateLanguageInteropTests

open System

open Barb.Compiler
open Barb.Representation

open Xunit

type DudeRecord = { Name: string; Sex: char }

type ParentWithObject = { State: string; Data: obj }

type DudeRecordWithInt = { Name: string; Age: int }
    with member t.GetAge() = t.Age

[<Fact>]
let ``should support dynamic property lookup on unknown types`` () =
    let childRec = { Name = "<NAME>"; Age = 20 }
    let parentRec = { State = "Washington"; Data = childRec :> obj }
    let predicate = buildExpr<ParentWithObject,bool> "Data.Name = \"<NAME>\" and Data.Age < 30"
    let result = predicate parentRec
    Assert.True(result)

[<Fact>]
let ``should support dynamic method lookup on unknown types`` () =
    let childRec = { Name = "<NAME>"; Age = 20 }
    let parentRec = { State = "Washington"; Data = childRec :> obj }
    let predicate = buildExpr<ParentWithObject,bool> "Data.Name = \"<NAME>\" and Data.GetAge() < 30"
    let result = predicate parentRec
    Assert.True(result)

[<Fact>] 
let ``should support no argument methods`` () =
    let testRecord = { Name = " <NAME> "; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Trim() = \"<NAME>\""
    let result = predicate testRecord
    Assert.True(result)

[<Fact>] 
let ``should support no argument methods on passed in constructs`` () =
    let testRecord = { Name = " <NAME> "; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "GetAge() = 20"
    let result = predicate testRecord
    Assert.True(result)

[<Fact>] 
let ``should support single argument methods`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Contains(\"<NAME>\")"
    let result = predicate testRecord
    Assert.True(result)

[<Fact>] 
let ``should support multi-argument methods`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Substring(0, 4) = \"Dude\""
    let result = predicate testRecord
    Assert.True(result)

[<Fact>]
let ``should support invoking a method on the results of a method call`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Substring(0, 4).Length = 4"
    let result = predicate testRecord
    Assert.True(result)

[<Fact>]
let ``should support invoking a method on the results of a subexpression`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "(Name.Substring(0, 4)).Length = 4"
    let result = predicate testRecord
    Assert.True(result)

type PropIndexerTester<'a,'b when 'a : comparison> (map: Map<'a,'b>) = 
    member this.Item
        with get(indexer: 'a) : 'b = map |> Map.find indexer

type IndexerRecord<'a,'b when 'a : comparison> = 
    {
        Name: string
        PropTable: PropIndexerTester<'a,'b>
    }

[<Fact>]
let ``should support property indexers`` () = 
    let testRecord = { Name = "<NAME>"; PropTable = new PropIndexerTester<int,int>([0..5] |> List.map (fun i -> i, i) |> Map.ofList) }
    let predicate = buildExpr<IndexerRecord<int,int>,bool> "PropTable.Item[0] = 0"
    let result = predicate testRecord
    Assert.True(result)    

[<Fact>]
let ``should support property indexers with strings`` () = 
    let testRecord = { Name = "<NAME>"; PropTable = new PropIndexerTester<string,string>(["one"; "two"; "three"] |> List.map (fun i -> i, i) |> Map.ofList) }
    let predicate = buildExpr<IndexerRecord<string,string>,bool> "PropTable.Item[\"two\"] = \"two\""
    let result = predicate testRecord
    Assert.True(result)    

[<Fact>]
let ``should directly support property indexers with strings`` () = 
    let testRecord = new PropIndexerTester<string,string>(["one"; "two"; "three"] |> List.map (fun i -> i, i) |> Map.ofList)
    let predicate = buildExpr<PropIndexerTester<string,string>,bool> "Item[\"two\"] = \"two\""
    let result = predicate testRecord
    Assert.True(result)    

type IndexedName = 
    {
        Name: string
        Index: int
    }   

[<Fact>]
let ``should correctly reduce the contents of indexers before applying`` () = 
    let testRecord = { Name = "<NAME>"; Index = 1 }
    let predicate = buildExpr<IndexedName,bool> "Name[Index] = \"u\""
    let result = predicate testRecord
    Assert.True(result)    

[<Fact>]
let ``should support using the results of calls to build incremental tuples`` () = 
    let testRecord = { Name = "<NAME>"; Index = 1 }
    let predicate = buildExpr<IndexedName,bool> "{Index .. 3} = (1, 2, 3)"
    let result = predicate testRecord
    Assert.True(result)  <commit_msg>Added test for IDictionary indexing (but missed commit)<commit_after>﻿module Barb.Tests.PredicateLanguageInteropTests

open System

open Barb.Compiler
open Barb.Representation

open Xunit

type DudeRecord = { Name: string; Sex: char }

type ParentWithObject = { State: string; Data: obj }

type DudeRecordWithInt = { Name: string; Age: int }
    with member t.GetAge() = t.Age

[<Fact>]
let ``should support dynamic property lookup on unknown types`` () =
    let childRec = { Name = "<NAME>"; Age = 20 }
    let parentRec = { State = "Washington"; Data = childRec :> obj }
    let predicate = buildExpr<ParentWithObject,bool> "Data.Name = \"<NAME>\" and Data.Age < 30"
    let result = predicate parentRec
    Assert.True(result)

[<Fact>]
let ``should support dynamic method lookup on unknown types`` () =
    let childRec = { Name = "<NAME>"; Age = 20 }
    let parentRec = { State = "Washington"; Data = childRec :> obj }
    let predicate = buildExpr<ParentWithObject,bool> "Data.Name = \"<NAME>\" and Data.GetAge() < 30"
    let result = predicate parentRec
    Assert.True(result)

[<Fact>] 
let ``should support no argument methods`` () =
    let testRecord = { Name = " <NAME> "; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Trim() = \"<NAME>\""
    let result = predicate testRecord
    Assert.True(result)

[<Fact>] 
let ``should support no argument methods on passed in constructs`` () =
    let testRecord = { Name = " <NAME> "; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "GetAge() = 20"
    let result = predicate testRecord
    Assert.True(result)

[<Fact>] 
let ``should support single argument methods`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Contains(\"<NAME>\")"
    let result = predicate testRecord
    Assert.True(result)

[<Fact>] 
let ``should support multi-argument methods`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Substring(0, 4) = \"Dude\""
    let result = predicate testRecord
    Assert.True(result)

[<Fact>]
let ``should support invoking a method on the results of a method call`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "Name.Substring(0, 4).Length = 4"
    let result = predicate testRecord
    Assert.True(result)

[<Fact>]
let ``should support invoking a method on the results of a subexpression`` () =
    let testRecord = { Name = "<NAME>"; Age = 20 }
    let predicate = buildExpr<DudeRecordWithInt,bool> "(Name.Substring(0, 4)).Length = 4"
    let result = predicate testRecord
    Assert.True(result)

type PropIndexerTester<'a,'b when 'a : comparison> (map: Map<'a,'b>) = 
    member this.Item
        with get(indexer: 'a) : 'b = map |> Map.find indexer

type IndexerRecord<'a,'b when 'a : comparison> = 
    {
        Name: string
        PropTable: PropIndexerTester<'a,'b>
    }

[<Fact>]
let ``should support property indexers`` () = 
    let testRecord = { Name = "<NAME>"; PropTable = new PropIndexerTester<int,int>([0..5] |> List.map (fun i -> i, i) |> Map.ofList) }
    let predicate = buildExpr<IndexerRecord<int,int>,bool> "PropTable.Item[0] = 0"
    let result = predicate testRecord
    Assert.True(result)    
    let predicate = buildExpr<IndexerRecord<int,int>,bool> "PropTable.Item[2] = 2"
    let result = predicate testRecord
    Assert.True(result)    

[<Fact>]
let ``should support property indexers with strings`` () = 
    let testRecord = { Name = "<NAME>"; PropTable = new PropIndexerTester<string,string>(["one"; "two"; "three"] |> List.map (fun i -> i, i) |> Map.ofList) }
    let predicate = buildExpr<IndexerRecord<string,string>,bool> "PropTable.Item[\"two\"] = \"two\""
    let result = predicate testRecord
    Assert.True(result)    

[<Fact>]
let ``should directly support property indexers with strings`` () = 
    let testRecord = new PropIndexerTester<string,string>(["one"; "two"; "three"] |> List.map (fun i -> i, i) |> Map.ofList)
    let predicate = buildExpr<PropIndexerTester<string,string>,bool> "Item[\"two\"] = \"two\""
    let result = predicate testRecord
    Assert.True(result)    

type IndexedName = 
    {
        Name: string
        Index: int
    }   

[<Fact>]
let ``should correctly reduce the contents of indexers before applying`` () = 
    let testRecord = { Name = "<NAME>"; Index = 1 }
    let predicate = buildExpr<IndexedName,bool> "Name[Index] = \"u\""
    let result = predicate testRecord
    Assert.True(result)    

open System.Collections.Generic

type DictTestRecord =  
    {
        Dict: IDictionary<string,string>
    }

[<Fact>]
let ``should propertly index into IDictionary`` () =
    let testRecord = { Dict = [("one", "1"); ("two", "2"); ("three", "3")] |> dict }
    let predicate = buildExpr<DictTestRecord,bool> "Dict['two'] = '2'"
    let result = predicate testRecord
    Assert.True(result)

let dictType = [|("one", "1")|] |> dict |> (fun t -> t.GetType()) |> (fun t -> t.GetInterfaces()) |> Array.map (fun i -> i.Name) 
//dictType.GetProperties

[<Fact>]
let ``should support using the results of calls to build incremental tuples`` () = 
    let testRecord = { Name = "<NAME>"; Index = 1 }
    let predicate = buildExpr<IndexedName,bool> "{Index .. 3} = (1, 2, 3)"
    let result = predicate testRecord
    Assert.True(result)  
{'fraction_non_alphanumeric': 0.1483456790123457, 'fraction_numerical': 0.008592592592592593, 'mean_word_length': 3.6006360745115855, 'pattern_counts': {'":': 0, '<': 116, '<?xml version=': 0, '>': 144, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5364322', 'n_tokens_mistral': 3299, 'n_tokens_neox': 3140, 'n_words': 952}