<commit_before>﻿(*
Copyright 2011 <NAME>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)

[<AutoOpen>]
module ReductionTests
open Xunit
open Swensen.Unquote
open Swensen.Utils

//we use this since expr don't support structural comparison
let decompiledReductions expr =
    reduceFully expr |> List.map decompile

[<Fact>]
let ``already reduced`` () =
    decompiledReductions <@ -18 @> =! ["-18"]
    decompiledReductions <@ (2, 3) @> =! ["(2, 3)"]
    decompiledReductions <@ [1;2;3;4] @> =! ["[1; 2; 3; 4]"]
    decompiledReductions <@ [|1;2;3;4|] @> =! ["[|1; 2; 3; 4|]"]

[<Fact>]
let ``coerce reduces right`` () =
    decompiledReductions <@ Set.ofSeq [1;1;2;4] @> =! [
        "Set.ofSeq [1; 1; 2; 4]"
        "set [1; 2; 4]"
    ]

[<Fact>]
let ``arithmetic expressions`` () = 
    decompiledReductions <@ (2 + (3 - 7)) * 9 @> =! [
        "(2 + (3 - 7)) * 9"
        "(2 + -4) * 9"
        "-2 * 9"
        "-18"
    ]

[<Fact>]
let ``simple lambda with application`` () =
    decompiledReductions <@ (fun i j -> i + j + 1) 1 2 @> =! [
        "(fun i j -> i + j + 1) 1 2"
        "4"
    ]

[<Fact>]
let ``lambda with non-reduced applications`` () =
    decompiledReductions <@ (fun i j -> i + j + 1) (1 + 2) 2 @> =! [
        "(fun i j -> i + j + 1) (1 + 2) 2"
        "(fun i j -> i + j + 1) 3 2"
        "6"
    ]

[<Fact>]
let ``lambda with application on lhs of + op call`` () =
    decompiledReductions <@ (fun i j k -> i + j + k) (2 + 5) 3 (4 + 17) + 12 @> =! [
        "(fun i j k -> i + j + k) (2 + 5) 3 (4 + 17) + 12"
        "(fun i j k -> i + j + k) 7 3 21 + 12"
        "31 + 12" //failing to evaluate this
        "43"
    ]

let f i j k = i + j + k
[<Fact>]
let ``function with application on lhs of + op call`` () =
    decompiledReductions <@ f (2 + 5) 3 (4 + 17) + 12 @> =! [
        "f (2 + 5) 3 (4 + 17) + 12"
        "f 7 3 21 + 12"
        "31 + 12"
        "43"
    ]

let ftuple i j = (i,j)
[<Fact>]
let ``function with application returns tuple`` () =
    decompiledReductions <@ ftuple 1 2 @> =! [
        "ftuple 1 2"
        "(1, 2)"
    ]

[<Fact>]
let ``function with application compared to tuple`` () =
    decompiledReductions <@ ftuple 1 2 = (1,2) @> =! [
        "ftuple 1 2 = (1, 2)"
        "(1, 2) = (1, 2)"
        "true"
    ]

[<Fact>]
let ``lambdas are reduced`` () =
    decompiledReductions <@ List.map (fun i -> i + 1) [1;2;3;4] = [2;3;4;5] @> =! [
        "List.map (fun i -> i + 1) [1; 2; 3; 4] = [2; 3; 4; 5]"
        "[2; 3; 4; 5] = [2; 3; 4; 5]"
        "true"
    ]

[<Fact>]
let ``new array with arg sub expressions`` () =
    decompiledReductions <@ [|1+1;2+(3-1);3|] = [|2;4;3|] @> =! [
        "[|1 + 1; 2 + (3 - 1); 3|] = [|2; 4; 3|]"
        "[|2; 2 + 2; 3|] = [|2; 4; 3|]"
        "[|2; 4; 3|] = [|2; 4; 3|]"
        "true"
    ]

open System
[<Fact>]
let ``new object is not reduced`` () =
    decompiledReductions <@ new string('c', 3) + "hello" @> =! [
        "new string('c', 3) + \"hello\""
        "\"ccc\" + \"hello\""
        "\"ccchello\""
    ]

[<Fact>]
let ``Sequential`` () =
    decompiledReductions <@ 1; 2; 3 @> =! [
        "1; 2; 3"
        "2; 3"
        "3"
    ]
    decompiledReductions <@ ignore 1; ignore 2; 3 @> =! [
        "ignore 1; ignore 2; 3"
        "(); ignore 2; 3"
        "ignore 2; 3"
        "(); 3"
        "3"
    ]

    decompiledReductions <@ 1 + 2 + 3 + 4; 1 + 2 + 3; 1 + 2  @> =! [
        "1 + 2 + 3 + 4; 1 + 2 + 3; 1 + 2"
        "3 + 3 + 4; 1 + 2 + 3; 1 + 2"
        "6 + 4; 1 + 2 + 3; 1 + 2"
        "10; 1 + 2 + 3; 1 + 2"
        "1 + 2 + 3; 1 + 2"
        "3 + 3; 1 + 2"
        "6; 1 + 2"
        "1 + 2"
        "3"
    ]
    
    decompiledReductions <@ (fun x -> x + 1); 2; 3 @> =! [
        "(fun x -> x + 1); 2; 3"
        "2; 3"
        "3"
    ]
    
    decompiledReductions <@ ignore (fun x -> x + 1); ignore 2; 3 @> =! [
        "ignore (fun x -> x + 1); ignore 2; 3"
        "(); ignore 2; 3"
        "ignore 2; 3"
        "(); 3"
        "3"
     ]

let doit (x:string) = (null:string)
[<Fact>]
let ``null reference exception`` () =
    let steps = decompiledReductions <@ 3 = (doit null).Length @>
    test <@ steps.Length = 3 @>
    let [step1; step2; step3] = steps
    step1 =! "3 = (doit null).Length"
    step2 =! "3 = null.Length"
    test <@ step3.StartsWith("System.NullReferenceException: Object reference not set to an instance of an object.") @>

[<Fact>]
let ``property get returns null but preserves ret type info and doesnt throw even though using Value lambda`` () =
    let doit (x:string) = (null:string)
    
    let steps = decompiledReductions <@ null = doit "asdf" @>
    
    test <@ steps.Length = 3 @>
    
    let [step1; step2; step3] = steps
    step1 =! "null = doit \"asdf\""
    step2 =! "null = null"
    step3 =! "true"

[<Fact>]
let ``nested lambda Value applications don't throw`` () =
    let doit (x:string) = (null:string)
    reduceFully <@ doit (doit (doit "asdf")) @>

[<Fact>]
let ``multi-var Value lambda application doesn't throw`` () =
    let doit1 (x:string) = (null:string)
    let doit2 (x:string) (y:string) = x + y
    let testExpr = <@ doit2 (doit1 "asdf") ("asdf" + "asdf")  @><commit_msg>make a couple tests cross platform<commit_after>﻿(*
Copyright 2011 <NAME>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)

[<AutoOpen>]
module ReductionTests
open Xunit
open Swensen.Unquote
open Swensen.Utils

//we use this since expr don't support structural comparison
let decompiledReductions expr =
    reduceFully expr |> List.map decompile

[<Fact>]
let ``already reduced`` () =
    decompiledReductions <@ -18 @> =! ["-18"]
    decompiledReductions <@ (2, 3) @> =! ["(2, 3)"]
    decompiledReductions <@ [1;2;3;4] @> =! ["[1; 2; 3; 4]"]
    decompiledReductions <@ [|1;2;3;4|] @> =! ["[|1; 2; 3; 4|]"]

[<Fact>]
let ``coerce reduces right`` () =
    decompiledReductions <@ Set.ofSeq [1;1;2;4] @> =! [
        "Set.ofSeq [1; 1; 2; 4]"
        "set [1; 2; 4]"
    ]

[<Fact>]
let ``arithmetic expressions`` () = 
    decompiledReductions <@ (2 + (3 - 7)) * 9 @> =! [
        "(2 + (3 - 7)) * 9"
        "(2 + -4) * 9"
        "-2 * 9"
        "-18"
    ]

[<Fact>]
let ``simple lambda with application`` () =
    decompiledReductions <@ (fun i j -> i + j + 1) 1 2 @> =! [
        "(fun i j -> i + j + 1) 1 2"
        "4"
    ]

[<Fact>]
let ``lambda with non-reduced applications`` () =
    decompiledReductions <@ (fun i j -> i + j + 1) (1 + 2) 2 @> =! [
        "(fun i j -> i + j + 1) (1 + 2) 2"
        "(fun i j -> i + j + 1) 3 2"
        "6"
    ]

[<Fact>]
let ``lambda with application on lhs of + op call`` () =
    decompiledReductions <@ (fun i j k -> i + j + k) (2 + 5) 3 (4 + 17) + 12 @> =! [
        "(fun i j k -> i + j + k) (2 + 5) 3 (4 + 17) + 12"
        "(fun i j k -> i + j + k) 7 3 21 + 12"
        "31 + 12" //failing to evaluate this
        "43"
    ]

let f i j k = i + j + k
[<Fact>]
let ``function with application on lhs of + op call`` () =
    decompiledReductions <@ f (2 + 5) 3 (4 + 17) + 12 @> =! [
        "f (2 + 5) 3 (4 + 17) + 12"
        "f 7 3 21 + 12"
        "31 + 12"
        "43"
    ]

let ftuple i j = (i,j)
[<Fact>]
let ``function with application returns tuple`` () =
    decompiledReductions <@ ftuple 1 2 @> =! [
        "ftuple 1 2"
        "(1, 2)"
    ]

[<Fact>]
let ``function with application compared to tuple`` () =
    decompiledReductions <@ ftuple 1 2 = (1,2) @> =! [
        "ftuple 1 2 = (1, 2)"
        "(1, 2) = (1, 2)"
        "true"
    ]

[<Fact>]
let ``lambdas are reduced`` () =
    decompiledReductions <@ List.map (fun i -> i + 1) [1;2;3;4] = [2;3;4;5] @> =! [
        "List.map (fun i -> i + 1) [1; 2; 3; 4] = [2; 3; 4; 5]"
        "[2; 3; 4; 5] = [2; 3; 4; 5]"
        "true"
    ]

[<Fact>]
let ``new array with arg sub expressions`` () =
    decompiledReductions <@ [|1+1;2+(3-1);3|] = [|2;4;3|] @> =! [
        "[|1 + 1; 2 + (3 - 1); 3|] = [|2; 4; 3|]"
        "[|2; 2 + 2; 3|] = [|2; 4; 3|]"
        "[|2; 4; 3|] = [|2; 4; 3|]"
        "true"
    ]

open System
[<Fact>]
let ``new object is not reduced`` () =
    decompiledReductions <@ new string('c', 3) + "hello" @> =! [
        "new string('c', 3) + \"hello\""
        "\"ccc\" + \"hello\""
        "\"ccchello\""
    ]

[<Fact>]
let ``Sequential`` () =
    decompiledReductions <@ 1; 2; 3 @> =! [
        "1; 2; 3"
        "2; 3"
        "3"
    ]
    decompiledReductions <@ ignore 1; ignore 2; 3 @> =! [
        "ignore 1; ignore 2; 3"
        "(); ignore 2; 3"
        "ignore 2; 3"
        "(); 3"
        "3"
    ]

    decompiledReductions <@ 1 + 2 + 3 + 4; 1 + 2 + 3; 1 + 2  @> =! [
        "1 + 2 + 3 + 4; 1 + 2 + 3; 1 + 2"
        "3 + 3 + 4; 1 + 2 + 3; 1 + 2"
        "6 + 4; 1 + 2 + 3; 1 + 2"
        "10; 1 + 2 + 3; 1 + 2"
        "1 + 2 + 3; 1 + 2"
        "3 + 3; 1 + 2"
        "6; 1 + 2"
        "1 + 2"
        "3"
    ]
    
    decompiledReductions <@ (fun x -> x + 1); 2; 3 @> =! [
        "(fun x -> x + 1); 2; 3"
        "2; 3"
        "3"
    ]
    
    decompiledReductions <@ ignore (fun x -> x + 1); ignore 2; 3 @> =! [
        "ignore (fun x -> x + 1); ignore 2; 3"
        "(); ignore 2; 3"
        "ignore 2; 3"
        "(); 3"
        "3"
     ]

let doit (x:string) = (null:string)
[<Fact>]
let ``null reference exception`` () =
    let steps = decompiledReductions <@ 3 = (doit null).Length @>
    test <@ steps.Length = 3 @>
    let [step1; step2; step3] = steps
    step1 =! "3 = (doit null).Length"
    step2 =! "3 = null.Length"
    test <@ step3.StartsWith("System.NullReferenceException: ") @>

[<Fact>]
let ``property get returns null but preserves ret type info and doesnt throw even though using Value lambda`` () =
    let doit (x:string) = (null:string)
    
    let steps = decompiledReductions <@ null = doit "asdf" @>
    
    test <@ steps.Length = 3 @>
    
    let [step1; step2; step3] = steps
    step1 =! "null = doit \"asdf\""
    step2 =! "null = null"
    step3 =! "true"

[<Fact>]
let ``nested lambda Value applications don't throw`` () =
    let doit (x:string) = (null:string)
    reduceFully <@ doit (doit (doit "asdf")) @>

[<Fact>]
let ``multi-var Value lambda application doesn't throw`` () =
    let doit1 (x:string) = (null:string)
    let doit2 (x:string) (y:string) = x + y
    let testExpr = <@ doit2 (doit1 "asdf") ("asdf" + "asdf")  @>
{'fraction_non_alphanumeric': 0.19341965235899256, 'fraction_numerical': 0.05817665838949982, 'mean_word_length': 2.11003861003861, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 125, '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': '5806159', 'n_tokens_mistral': 4865, 'n_tokens_neox': 4346, 'n_words': 1421}