1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.cst;
7   
8   import static gov.nist.secauto.metaschema.core.metapath.TestUtils.eqname;
9   import static org.junit.jupiter.api.Assertions.assertEquals;
10  
11  import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
12  import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression;
13  import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression.ResultType;
14  import gov.nist.secauto.metaschema.core.metapath.StaticContext;
15  import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
16  import gov.nist.secauto.metaschema.core.testing.model.mocking.MockedDocumentGenerator;
17  
18  import org.junit.jupiter.api.Test;
19  
20  /**
21   * Unit tests for anonymous function calls in Metapath expressions.
22   * <p>
23   * These tests validate the compilation and execution of anonymous functions as
24   * defined in the Metaschema specification.
25   */
26  class AnonymousFunctionCallTest {
27    private static final String NS = "http://example.com/ns";
28  
29    /**
30     * Tests the basic functionality of anonymous function definition and execution.
31     * This test validates:
32     * <ul>
33     * <li>Function definition using the 'let' syntax
34     * <li>Function execution with string parameters
35     * <li>String concatenation within the function body
36     * </ul>
37     */
38    @Test
39    void test() {
40      StaticContext staticContext = StaticContext.builder()
41          .namespace("ex", NS)
42          .build();
43      DynamicContext dynamicContext = new DynamicContext(staticContext);
44  
45      String metapath = "let $function := function($str) as meta:string { fn:concat('extra ',$str) } "
46          + "return $function('cool')";
47  
48      assertEquals(
49          "extra cool",
50          IMetapathExpression.compile(metapath, staticContext).evaluateAs(
51              null,
52              IMetapathExpression.ResultType.STRING,
53              dynamicContext));
54    }
55  
56    @Test
57    void testMultipleParameters() {
58      StaticContext staticContext = StaticContext.builder()
59          .namespace("ex", NS)
60          .build();
61      DynamicContext dynamicContext = new DynamicContext(staticContext);
62      String metapath = "function ($argument1 as meta:string, $argument2 as meta:string) as meta:string { $argument2 }";
63      dynamicContext.bindVariableValue(eqname(NS, "boom"),
64          IMetapathExpression.compile(metapath, staticContext).evaluate(null, dynamicContext));
65      String result = IMetapathExpression.compile("$ex:boom('a', 'b')", staticContext).evaluateAs(null, ResultType.STRING,
66          dynamicContext);
67      assertEquals(result, "b");
68    }
69  
70    @Test
71    void testDifferentReturnTypes() {
72      // FIXME: Add test for functions returning different types
73    }
74  
75    @Test
76    void testErrorCases() {
77      // FIXME: Add test for invalid function definitions
78    }
79  
80    /**
81     * This tests for a regression of the issue <a href=
82     * "https://github.com/metaschema-framework/metaschema-java/issues/323">metaschema-framework/metaschema-java#323</a>.
83     */
84    @Test
85    void testFunctionParameterUsingFlagNodeArgument() {
86      StaticContext staticContext = StaticContext.builder()
87          .namespace("ex", NS)
88          .defaultModelNamespace(NS)
89          .build();
90      INodeItem flag = MockedDocumentGenerator.generateOrphanedFlagNodeItem();
91      DynamicContext dynamicContext = new DynamicContext(staticContext);
92      dynamicContext.bindVariableValue(
93          eqname(NS, "should-dereference-param-flag-value"),
94          IMetapathExpression
95              .compile("function($arg as meta:string) as meta:string { $arg }", dynamicContext.getStaticContext())
96              .evaluate(flag, dynamicContext));
97      String result
98          = IMetapathExpression.compile("$ex:should-dereference-param-flag-value(.)", dynamicContext.getStaticContext())
99              .evaluateAs(flag, ResultType.STRING, dynamicContext);
100     assertEquals(result, "flag");
101   }
102 }