1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.propagation.events;
18  
19  import java.util.Collections;
20  import java.util.NoSuchElementException;
21  
22  import org.hipparchus.util.Binary64;
23  import org.hipparchus.util.Binary64Field;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  import org.mockito.Mockito;
28  import org.orekit.propagation.FieldSpacecraftState;
29  import org.orekit.propagation.SpacecraftState;
30  import org.orekit.propagation.events.handlers.FieldEventHandler;
31  import org.orekit.propagation.events.intervals.FieldAdaptableInterval;
32  import org.orekit.time.FieldAbsoluteDate;
33  
34  /**
35   * Unit tests for {@link BooleanDetector}.
36   *
37   * @author Evan Ward
38   */
39  public class FieldAndDetectorTest {
40  
41      /** first operand. */
42      private MockDetector a;
43      /** second operand. */
44      private MockDetector b;
45      /** null (except for date) */
46      private FieldSpacecraftState<Binary64> s;
47      /** subject under test */
48      private FieldBooleanDetector<Binary64> and;
49  
50      /** create subject under test and dependencies. */
51      @SuppressWarnings("unchecked")
52      @BeforeEach
53      public void setUp() {
54          a = new MockDetector();
55          b = new MockDetector();
56          s = Mockito.mock(FieldSpacecraftState.class);
57          Mockito.when(s.getDate()).thenReturn(FieldAbsoluteDate.getArbitraryEpoch(Binary64Field.getInstance()));
58          and = FieldBooleanDetector.andCombine(a, b);
59      }
60  
61      /**
62       * check {@link BooleanDetector#g(SpacecraftState)}.
63       */
64      @Test
65      public void testG() {
66          // test both zero
67          a.g = b.g = new Binary64(0.0);
68          Assertions.assertEquals(0.0, and.g(s).getReal(), 0);
69  
70          // test either zero
71          a.g = new Binary64(1);
72          b.g = new Binary64(0);
73          Assertions.assertEquals(0.0, and.g(s).getReal(), 0);
74          a.g = new Binary64(0);
75          b.g = new Binary64(1);
76          Assertions.assertEquals(0.0, and.g(s).getReal(), 0);
77  
78          // test either negative
79          a.g = new Binary64(0);
80          b.g = new Binary64(-1);
81          Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
82          a.g = new Binary64(1);
83          b.g = new Binary64(-1);
84          Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
85          a.g = new Binary64(-1);
86          b.g = new Binary64(0);
87          Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
88          a.g = new Binary64(-1);
89          b.g = new Binary64(1);
90          Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
91          a.g = new Binary64(-1);
92          b.g = new Binary64(-1);
93          Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
94  
95          // test both positive
96          a.g = new Binary64(1);
97          b.g = new Binary64(1);
98          Assertions.assertTrue(and.g(s).getReal() > 0, "positive");
99  
100     }
101 
102     /**
103      * check {@link BooleanDetector} for cancellation.
104      */
105     @Test
106     public void testCancellation() {
107         a.g = new Binary64(-1e-10);
108         b.g = new Binary64(1e10);
109         Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
110         a.g = new Binary64(1e10);
111         b.g = new Binary64(-1e-10);
112         Assertions.assertTrue(and.g(s).getReal() < 0, "negative");
113         a.g = new Binary64(1e10);
114         b.g = new Binary64(1e-10);
115         Assertions.assertTrue(and.g(s).getReal() > 0, "positive");
116         a.g = new Binary64(1e-10);
117         b.g = new Binary64(1e10);
118         Assertions.assertTrue(and.g(s).getReal() > 0, "positive");
119     }
120 
121     /**
122      * Check wrapped detectors are initialized.
123      */
124     @SuppressWarnings("unchecked")
125     @Test
126     public void testInit() {
127         // setup
128         FieldEventDetector<Binary64> a = Mockito.mock(FieldEventDetector.class);
129         Mockito.when(a.getMaxCheckInterval()).thenReturn(FieldAdaptableInterval.of(AbstractDetector.DEFAULT_MAX_CHECK));
130         Mockito.when(a.getThreshold()).thenReturn(new Binary64(AbstractDetector.DEFAULT_THRESHOLD));
131         FieldEventDetector<Binary64> b = Mockito.mock(FieldEventDetector.class);
132         Mockito.when(b.getMaxCheckInterval()).thenReturn(FieldAdaptableInterval.of(AbstractDetector.DEFAULT_MAX_CHECK));
133         Mockito.when(b.getThreshold()).thenReturn(new Binary64(AbstractDetector.DEFAULT_THRESHOLD));
134         FieldEventHandler<Binary64> c = Mockito.mock(FieldEventHandler.class);
135         FieldBooleanDetector<Binary64> and = FieldBooleanDetector.andCombine(a, b).withHandler(c);
136         FieldAbsoluteDate<Binary64> t = FieldAbsoluteDate.getCCSDSEpoch(Binary64Field.getInstance());
137         s = Mockito.mock(FieldSpacecraftState.class);
138         Mockito.when(s.getDate()).thenReturn(t.shiftedBy(60.0));
139 
140         // action
141         and.init(s, t);
142 
143         // verify
144         Assertions.assertEquals(2, and.getDetectors().size());
145         Mockito.verify(a).init(s, t);
146         Mockito.verify(b).init(s, t);
147         Mockito.verify(c).init(s, t, and);
148     }
149 
150     /** check when no operands are passed to the constructor. */
151     @Test
152     public void testZeroDetectors() {
153         // action
154         try {
155             BooleanDetector.andCombine(Collections.emptyList());
156             Assertions.fail("Expected Exception");
157         } catch (NoSuchElementException e) {
158             // expected
159         }
160     }
161 
162     /** Mock detector to set the g function to arbitrary values. */
163     private static class MockDetector implements FieldEventDetector<Binary64> {
164 
165         /** value to return from {@link #g(SpacecraftState)}. */
166         public Binary64 g = new Binary64(0);
167 
168         @Override
169         public void init(FieldSpacecraftState<Binary64> s0, FieldAbsoluteDate<Binary64> t) {
170 
171         }
172 
173         @Override
174         public Binary64 g(FieldSpacecraftState<Binary64> s) {
175             return this.g;
176         }
177 
178         @Override
179         public FieldEventHandler<Binary64> getHandler() {
180             return (state, detector, increasing) -> null;
181         }
182 
183         @Override
184         public FieldEventDetectionSettings<Binary64> getDetectionSettings() {
185             return new FieldEventDetectionSettings<>(Binary64Field.getInstance(), EventDetectionSettings.getDefaultEventDetectionSettings());
186         }
187     }
188 }