]> git.basschouten.com Git - openhab-addons.git/blob
93c6aec72d3a0e7e649152991148f5c230776809
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.astro.internal.calc;
14
15 import static org.junit.jupiter.api.Assertions.*;
16
17 import java.util.Calendar;
18 import java.util.GregorianCalendar;
19 import java.util.TimeZone;
20
21 import org.junit.jupiter.api.BeforeEach;
22 import org.junit.jupiter.api.Disabled;
23 import org.junit.jupiter.api.Test;
24 import org.openhab.binding.astro.internal.model.Sun;
25 import org.openhab.binding.astro.internal.model.SunPhaseName;
26
27 /***
28  * Specific unit tests to check if {@link SunCalc} generates correct data for
29  * Amsterdam city on 27 February 2019. In particular the following cases are
30  * covered:
31  * <ul>
32  * <li>checks if generated data are the same (with some accuracy) as produced by
33  * haevens-above.com</li>
34  * <li>checks if the generated {@link Sun#getAllRanges()} are consistent with
35  * each other</li>
36  * </ul>
37  *
38  * @author Witold Markowski - Initial contribution
39  * @see <a href="https://github.com/openhab/openhab-addons/issues/5006">[astro]
40  *      Sun Phase returns UNDEF</a>
41  * @see <a href="https://www.heavens-above.com/sun.aspx">Heavens Above Sun</a>
42  */
43 public class SunCalcTest {
44
45     private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Europe/Amsterdam");
46     private static final Calendar FEB_27_2019 = SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 1, 0, TIME_ZONE);
47     private static final double AMSTERDAM_LATITUDE = 52.367607;
48     private static final double AMSTERDAM_LONGITUDE = 4.8978293;
49     private static final double AMSTERDAM_ALTITUDE = 0.0;
50     private static final int ACCURACY_IN_MILLIS = 3 * 60 * 1000;
51
52     private SunCalc sunCalc;
53
54     @BeforeEach
55     public void init() {
56         sunCalc = new SunCalc();
57     }
58
59     @Test
60     public void testGetSunInfoForOldDate() {
61         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
62
63         assertNotNull(sun.getNight());
64
65         assertNotNull(sun.getAstroDawn());
66         assertNotNull(sun.getNauticDawn());
67         assertNotNull(sun.getCivilDawn());
68
69         assertNotNull(sun.getRise());
70
71         assertNotNull(sun.getDaylight());
72         assertNotNull(sun.getNoon());
73         assertNotNull(sun.getSet());
74
75         assertNotNull(sun.getCivilDusk());
76         assertNotNull(sun.getNauticDusk());
77         assertNotNull(sun.getAstroDusk());
78         assertNotNull(sun.getNight());
79
80         assertNotNull(sun.getMorningNight());
81         assertNotNull(sun.getEveningNight());
82
83         // for an old date the phase should also be calculated
84         assertNotNull(sun.getPhase().getName());
85     }
86
87     @Test
88     public void testGetSunInfoForAstronomicalDawnAccuracy() {
89         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
90
91         // expected result from haevens-above.com is 27 Feb 2019 05:39 till 06:18
92         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 5, 39, TIME_ZONE).getTimeInMillis(),
93                 sun.getAstroDawn().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
94         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 18, TIME_ZONE).getTimeInMillis(),
95                 sun.getAstroDawn().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
96     }
97
98     @Test
99     public void testGetSunInfoForNauticDawnAccuracy() {
100         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
101
102         // expected result from haevens-above.com is 27 Feb 2019 06:18 till 06:58
103         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 18, TIME_ZONE).getTimeInMillis(),
104                 sun.getNauticDawn().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
105         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 58, TIME_ZONE).getTimeInMillis(),
106                 sun.getNauticDawn().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
107     }
108
109     @Test
110     public void testGetSunInfoForCivilDawnAccuracy() {
111         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
112
113         // expected result from haevens-above.com is 27 Feb 2019 06:58 till 07:32
114         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 58, TIME_ZONE).getTimeInMillis(),
115                 sun.getCivilDawn().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
116         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 7, 32, TIME_ZONE).getTimeInMillis(),
117                 sun.getCivilDawn().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
118     }
119
120     @Test
121     public void testGetSunInfoForRiseAccuracy() {
122         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
123
124         // expected result from haevens-above.com is 27 Feb 2019 07:32
125         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 7, 32, TIME_ZONE).getTimeInMillis(),
126                 sun.getRise().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
127     }
128
129     @Test
130     public void testGetSunInfoForSunNoonAccuracy() {
131         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
132
133         // expected result from haevens-above.com is 27 Feb 2019 12:54
134         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 12, 54, TIME_ZONE).getTimeInMillis(),
135                 sun.getNoon().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
136     }
137
138     @Test
139     public void testGetSunInfoForSetAccuracy() {
140         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
141
142         // expected result from haevens-above.com is 27 Feb 2019 18:15
143         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, TIME_ZONE).getTimeInMillis(),
144                 sun.getSet().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
145     }
146
147     @Test
148     public void testGetSunInfoForCivilDuskAccuracy() {
149         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
150
151         // expected result from haevens-above.com is 27 Feb 2019 18:15 till 18:50
152         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, TIME_ZONE).getTimeInMillis(),
153                 sun.getCivilDusk().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
154         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 50, TIME_ZONE).getTimeInMillis(),
155                 sun.getCivilDusk().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
156     }
157
158     @Test
159     public void testGetSunInfoForNauticDuskAccuracy() {
160         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
161
162         // expected result from haevens-above.com is 27 Feb 2019 18:50 till 19:29
163         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 50, TIME_ZONE).getTimeInMillis(),
164                 sun.getNauticDusk().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
165         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 19, 29, TIME_ZONE).getTimeInMillis(),
166                 sun.getNauticDusk().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
167     }
168
169     @Test
170     public void testGetSunInfoForAstronomicalDuskAccuracy() {
171         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
172
173         // expected result from haevens-above.com is 27 Feb 2019 19:29 till 20:09
174         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 19, 29, TIME_ZONE).getTimeInMillis(),
175                 sun.getAstroDusk().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
176         assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 20, 9, TIME_ZONE).getTimeInMillis(),
177                 sun.getAstroDusk().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
178     }
179
180     @Test
181     @Disabled
182     public void testRangesForCoherenceBetweenNightEndAndAstroDawnStart() {
183         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
184
185         assertEquals(sun.getAllRanges().get(SunPhaseName.NIGHT).getEnd(),
186                 sun.getAllRanges().get(SunPhaseName.ASTRO_DAWN).getStart());
187     }
188
189     @Test
190     public void testRangesForCoherenceBetweenMorningNightEndAndAstroDawnStart() {
191         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
192
193         assertEquals(sun.getAllRanges().get(SunPhaseName.MORNING_NIGHT).getEnd(),
194                 sun.getAllRanges().get(SunPhaseName.ASTRO_DAWN).getStart());
195     }
196
197     @Test
198     public void testRangesForCoherenceBetweenAstroDownEndAndNauticDawnStart() {
199         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
200
201         assertEquals(sun.getAllRanges().get(SunPhaseName.ASTRO_DAWN).getEnd(),
202                 sun.getAllRanges().get(SunPhaseName.NAUTIC_DAWN).getStart());
203     }
204
205     @Test
206     public void testRangesForCoherenceBetweenNauticDawnEndAndCivilDawnStart() {
207         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
208
209         assertEquals(sun.getAllRanges().get(SunPhaseName.NAUTIC_DAWN).getEnd(),
210                 sun.getAllRanges().get(SunPhaseName.CIVIL_DAWN).getStart());
211     }
212
213     @Test
214     public void testRangesForCoherenceBetweenCivilDawnEndAndSunRiseStart() {
215         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
216
217         assertEquals(sun.getAllRanges().get(SunPhaseName.CIVIL_DAWN).getEnd(),
218                 sun.getAllRanges().get(SunPhaseName.SUN_RISE).getStart());
219     }
220
221     @Test
222     public void testRangesForCoherenceBetweenSunRiseEndAndDaylightStart() {
223         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
224
225         assertEquals(sun.getAllRanges().get(SunPhaseName.SUN_RISE).getEnd(),
226                 sun.getAllRanges().get(SunPhaseName.DAYLIGHT).getStart());
227     }
228
229     @Test
230     public void testRangesForCoherenceBetweenDaylightEndAndSunSetStart() {
231         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
232
233         assertEquals(sun.getAllRanges().get(SunPhaseName.DAYLIGHT).getEnd(),
234                 sun.getAllRanges().get(SunPhaseName.SUN_SET).getStart());
235     }
236
237     @Test
238     public void testRangesForCoherenceBetweenSunSetEndAndCivilDuskStart() {
239         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
240
241         assertEquals(sun.getAllRanges().get(SunPhaseName.SUN_SET).getEnd(),
242                 sun.getAllRanges().get(SunPhaseName.CIVIL_DUSK).getStart());
243     }
244
245     @Test
246     public void testRangesForCoherenceBetweenCivilDuskEndAndNauticDuskStart() {
247         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
248
249         assertEquals(sun.getAllRanges().get(SunPhaseName.CIVIL_DUSK).getEnd(),
250                 sun.getAllRanges().get(SunPhaseName.NAUTIC_DUSK).getStart());
251     }
252
253     @Test
254     public void testRangesForCoherenceBetweenNauticDuskEndAndAstroDuskStart() {
255         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
256
257         assertEquals(sun.getAllRanges().get(SunPhaseName.NAUTIC_DUSK).getEnd(),
258                 sun.getAllRanges().get(SunPhaseName.ASTRO_DUSK).getStart());
259     }
260
261     @Test
262     public void testRangesForCoherenceBetweenAstroDuskEndAndNightStart() {
263         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
264
265         assertEquals(sun.getAllRanges().get(SunPhaseName.ASTRO_DUSK).getEnd(),
266                 sun.getAllRanges().get(SunPhaseName.NIGHT).getStart());
267     }
268
269     @Test
270     public void testRangesForCoherenceBetweenAstroDuskEndAndEveningNightStart() {
271         Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE, false);
272
273         assertEquals(sun.getAllRanges().get(SunPhaseName.ASTRO_DUSK).getEnd(),
274                 sun.getAllRanges().get(SunPhaseName.EVENING_NIGHT).getStart());
275     }
276
277     @Test
278     public void testIssue7642CivilDawnEnd() {
279         TimeZone tZone = TimeZone.getTimeZone("Europe/London");
280         Calendar tDate = SunCalcTest.newCalendar(2020, Calendar.MAY, 13, 5, 12, tZone);
281
282         Sun sun = sunCalc.getSunInfo(tDate, 53.524695, -2.4, 0.0, true);
283         assertEquals(SunPhaseName.CIVIL_DAWN, sun.getPhase().getName());
284     }
285
286     @Test
287     public void testIssue7642SunRiseStart() {
288         // SunCalc.ranges was not sorted, causing unexpected output in corner cases.
289         TimeZone tZone = TimeZone.getTimeZone("Europe/London");
290         Calendar tDate = SunCalcTest.newCalendar(2020, Calendar.MAY, 13, 5, 13, tZone);
291
292         Sun sun = sunCalc.getSunInfo(tDate, 53.524695, -2.4, 0.0, true);
293         assertEquals(SunPhaseName.SUN_RISE, sun.getPhase().getName());
294     }
295
296     @Test
297     public void testIssue7642DaylightStart() {
298         TimeZone tZone = TimeZone.getTimeZone("Europe/London");
299         Calendar tDate = SunCalcTest.newCalendar(2020, Calendar.MAY, 13, 5, 18, tZone);
300
301         Sun sun = sunCalc.getSunInfo(tDate, 53.524695, -2.4, 0.0, true);
302         assertEquals(SunPhaseName.DAYLIGHT, sun.getPhase().getName());
303     }
304
305     /***
306      * Constructs a <code>GregorianCalendar</code> with the given date and time set
307      * for the provided time zone.
308      *
309      * @param year
310      *            the value used to set the <code>YEAR</code> calendar field in the
311      *            calendar.
312      * @param month
313      *            the value used to set the <code>MONTH</code> calendar field in the
314      *            calendar. Month value is 0-based. e.g., 0 for January.
315      * @param dayOfMonth
316      *            the value used to set the <code>DAY_OF_MONTH</code> calendar field
317      *            in the calendar.
318      * @param hourOfDay
319      *            the value used to set the <code>HOUR_OF_DAY</code> calendar field
320      *            in the calendar.
321      * @param minute
322      *            the value used to set the <code>MINUTE</code> calendar field in
323      *            the calendar.
324      * @param zone
325      *            the given time zone.
326      * @return
327      */
328     private static Calendar newCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute, TimeZone zone) {
329         Calendar result = new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute);
330         result.setTimeZone(zone);
331
332         return result;
333     }
334
335     @Test
336     public void testAstroAndMeteoSeasons() {
337         Sun meteoSun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE,
338                 true);
339         Sun equiSun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE,
340                 false);
341
342         assertEquals(meteoSun.getSeason().getSpring().get(Calendar.MONTH),
343                 equiSun.getSeason().getSpring().get(Calendar.MONTH));
344         assertEquals(meteoSun.getSeason().getSpring().get(Calendar.YEAR),
345                 equiSun.getSeason().getSpring().get(Calendar.YEAR));
346         assertEquals(1, meteoSun.getSeason().getSpring().get(Calendar.DAY_OF_MONTH));
347         assertFalse(meteoSun.getSeason().getSpring().get(Calendar.DAY_OF_MONTH) == equiSun.getSeason().getSpring()
348                 .get(Calendar.DAY_OF_MONTH));
349     }
350 }