• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1996-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 
9 /* Test CalendarAstronomer for C++ */
10 
11 #include "unicode/utypes.h"
12 #include "string.h"
13 #include "unicode/locid.h"
14 
15 #if !UCONFIG_NO_FORMATTING
16 
17 #include "astro.h"
18 #include "astrotst.h"
19 #include "cmemory.h"
20 #include "gregoimp.h" // for Math
21 #include "unicode/simpletz.h"
22 
23 
24 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
25 
AstroTest()26 AstroTest::AstroTest(): gc(nullptr) {
27 }
28 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)29 void AstroTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
30 {
31     if (exec) logln("TestSuite AstroTest");
32     switch (index) {
33       // CASE(0,FooTest);
34       CASE(0,TestSolarLongitude);
35       CASE(1,TestLunarPosition);
36       CASE(2,TestCoordinates);
37       CASE(3,TestCoverage);
38       CASE(4,TestBasics);
39       CASE(5,TestMoonAge);
40     default: name = ""; break;
41     }
42 }
43 
44 #undef CASE
45 
46 #define ASSERT_OK(x) UPRV_BLOCK_MACRO_BEGIN { \
47     if(U_FAILURE(x)) { \
48         dataerrln("%s:%d: %s\n", __FILE__, __LINE__, u_errorName(x)); \
49         return; \
50     } \
51 } UPRV_BLOCK_MACRO_END
52 
53 
init(UErrorCode & status)54 void AstroTest::init(UErrorCode &status) {
55   if(U_FAILURE(status)) return;
56 
57   if(gc != nullptr) {
58     dataerrln("Err: init() called twice!");
59     close(status);
60     if(U_SUCCESS(status)) {
61       status = U_INTERNAL_PROGRAM_ERROR;
62     }
63   }
64 
65   if(U_FAILURE(status)) return;
66 
67   gc = Calendar::createInstance(TimeZone::getGMT()->clone(), status);
68 }
69 
close(UErrorCode &)70 void AstroTest::close(UErrorCode &/*status*/) {
71   if(gc != nullptr) {
72     delete gc;
73     gc = nullptr;
74   }
75 }
76 
TestSolarLongitude()77 void AstroTest::TestSolarLongitude() {
78   UErrorCode status = U_ZERO_ERROR;
79   init(status);
80   ASSERT_OK(status);
81 
82   struct {
83     int32_t d[5]; double f ;
84   } tests[] = {
85     { { 1980, 7, 27, 0, 00 },  124.114347 },
86     { { 1988, 7, 27, 00, 00 },  124.187732 }
87   };
88 
89   logln("");
90   for (uint32_t i = 0; i < UPRV_LENGTHOF(tests); i++) {
91     gc->clear();
92     gc->set(tests[i].d[0], tests[i].d[1]-1, tests[i].d[2], tests[i].d[3], tests[i].d[4]);
93 
94     CalendarAstronomer astro(gc->getTime(status));
95 
96     astro.getSunLongitude();
97   }
98   close(status);
99   ASSERT_OK(status);
100 }
101 
102 
103 
TestLunarPosition()104 void AstroTest::TestLunarPosition() {
105   UErrorCode status = U_ZERO_ERROR;
106   init(status);
107   ASSERT_OK(status);
108 
109   static const double tests[][7] = {
110     { 1979, 2, 26, 16, 00,  0, 0 }
111   };
112   logln("");
113 
114   for (int32_t i = 0; i < UPRV_LENGTHOF(tests); i++) {
115     gc->clear();
116     gc->set((int32_t)tests[i][0], (int32_t)tests[i][1]-1, (int32_t)tests[i][2], (int32_t)tests[i][3], (int32_t)tests[i][4]);
117     CalendarAstronomer astro(gc->getTime(status));
118 
119     const CalendarAstronomer::Equatorial& result = astro.getMoonPosition();
120     logln((UnicodeString)"Moon position is " + result.toString() + (UnicodeString)";  " /* + result->toHmsString()*/);
121   }
122 
123   close(status);
124   ASSERT_OK(status);
125 }
126 
127 
128 
TestCoordinates()129 void AstroTest::TestCoordinates() {
130   UErrorCode status = U_ZERO_ERROR;
131   init(status);
132   ASSERT_OK(status);
133 
134   CalendarAstronomer::Equatorial result;
135   CalendarAstronomer astro;
136   astro.eclipticToEquatorial(result, 139.686111 * CalendarAstronomer::PI / 180.0, 4.875278* CalendarAstronomer::PI / 180.0);
137   logln((UnicodeString)"result is " + result.toString() + (UnicodeString)";  " /* + result.toHmsString()*/ );
138   close(status);
139   ASSERT_OK(status);
140 }
141 
142 
143 
TestCoverage()144 void AstroTest::TestCoverage() {
145   UErrorCode status = U_ZERO_ERROR;
146   init(status);
147   ASSERT_OK(status);
148   GregorianCalendar *cal = new GregorianCalendar(1958, UCAL_AUGUST, 15,status);
149   UDate then = cal->getTime(status);
150   CalendarAstronomer *myastro = new CalendarAstronomer(then);
151   ASSERT_OK(status);
152 
153   //Latitude:  34 degrees 05' North
154   //Longitude:  118 degrees 22' West
155   double laLat = 34 + 5./60, laLong = 360 - (118 + 22./60);
156 
157   double eclLat = laLat * CalendarAstronomer::PI / 360;
158   double eclLong = laLong * CalendarAstronomer::PI / 360;
159 
160   CalendarAstronomer::Equatorial eq;
161 
162   CalendarAstronomer *astronomers[] = {
163     myastro, myastro, myastro // check cache
164   };
165 
166   for (uint32_t i = 0; i < UPRV_LENGTHOF(astronomers); ++i) {
167     CalendarAstronomer *anAstro = astronomers[i];
168 
169     //logln("astro: " + astro);
170     logln((UnicodeString)"   date: " + anAstro->getTime());
171     logln((UnicodeString)"   equ ecl: " + (anAstro->eclipticToEquatorial(eq,eclLat,eclLong)).toString());
172   }
173 
174   delete myastro;
175   delete cal;
176 
177   close(status);
178   ASSERT_OK(status);
179 }
180 
TestBasics()181 void AstroTest::TestBasics() {
182   UErrorCode status = U_ZERO_ERROR;
183   init(status);
184   if (U_FAILURE(status)) {
185     dataerrln("Got error: %s", u_errorName(status));
186     return;
187   }
188 
189   // Check that our JD computation is the same as the book's (p. 88)
190   GregorianCalendar cal3(TimeZone::getGMT()->clone(), Locale::getUS(), status);
191   LocalPointer<DateFormat> d3(DateFormat::createDateTimeInstance(DateFormat::MEDIUM,DateFormat::MEDIUM,Locale::getUS()));
192   if (d3.isNull()) {
193       dataerrln("Got error: %s", u_errorName(status));
194       close(status);
195       return;
196   }
197   d3->setTimeZone(*TimeZone::getGMT());
198   cal3.clear();
199   cal3.set(UCAL_YEAR, 1980);
200   cal3.set(UCAL_MONTH, UCAL_JULY);
201   cal3.set(UCAL_DATE, 2);
202   logln("cal3[a]=%.1lf, d=%d\n", cal3.getTime(status), cal3.get(UCAL_JULIAN_DAY,status));
203   {
204     UnicodeString s;
205     logln(UnicodeString("cal3[a] = ") + d3->format(cal3.getTime(status),s));
206   }
207   cal3.clear();
208   cal3.set(UCAL_YEAR, 1980);
209   cal3.set(UCAL_MONTH, UCAL_JULY);
210   cal3.set(UCAL_DATE, 27);
211   logln("cal3=%.1lf, d=%d\n", cal3.getTime(status), cal3.get(UCAL_JULIAN_DAY,status));
212 
213   ASSERT_OK(status);
214   {
215     UnicodeString s;
216     logln(UnicodeString("cal3 = ") + d3->format(cal3.getTime(status),s));
217   }
218   CalendarAstronomer astro(cal3.getTime(status));
219   double jd = astro.getJulianDay() - 2447891.5;
220   double exp = -3444.;
221   if (jd == exp) {
222     UnicodeString s;
223     logln(d3->format(cal3.getTime(status),s) + " => " + jd);
224   } else {
225     UnicodeString s;
226     errln("FAIL: " + d3->format(cal3.getTime(status), s) + " => " + jd +
227           ", expected " + exp);
228   }
229 
230   //        cal3.clear();
231   //        cal3.set(cal3.YEAR, 1990);
232   //        cal3.set(cal3.MONTH, Calendar.JANUARY);
233   //        cal3.set(cal3.DATE, 1);
234   //        cal3.add(cal3.DATE, -1);
235   //        astro.setDate(cal3.getTime());
236   //        astro.foo();
237 
238   ASSERT_OK(status);
239   close(status);
240   ASSERT_OK(status);
241 
242 }
243 
TestMoonAge()244 void AstroTest::TestMoonAge(){
245 	UErrorCode status = U_ZERO_ERROR;
246 	init(status);
247 	ASSERT_OK(status);
248 
249 	// more testcases are around the date 05/20/2012
250 	//ticket#3785  UDate ud0 = 1337557623000.0;
251 	static const double testcase[][10] = {{2012, 5, 20 , 16 , 48, 59},
252 	                {2012, 5, 20 , 16 , 47, 34},
253 	                {2012, 5, 21, 00, 00, 00},
254 	                {2012, 5, 20, 14, 55, 59},
255 	                {2012, 5, 21, 7, 40, 40},
256 	                {2023, 9, 25, 10,00, 00},
257 	                {2008, 7, 7, 15, 00, 33},
258 	                {1832, 9, 24, 2, 33, 41 },
259 	                {2016, 1, 31, 23, 59, 59},
260 	                {2099, 5, 20, 14, 55, 59}
261 	        };
262 	// Moon phase angle - Got from http://www.moonsystem.to/checkupe.htm
263 	static const double angle[] = {356.8493418421329, 356.8386760059673, 0.09625415252237701, 355.9986960782416, 3.5714026601303317, 124.26906744384183, 59.80247650195558,
264 									357.54163205513123, 268.41779281511094, 4.82340276581624};
265 	static const double precision = CalendarAstronomer::PI/32;
266 	for (int32_t i = 0; i < UPRV_LENGTHOF(testcase); i++) {
267 		gc->clear();
268 		logln((UnicodeString)"CASE["+i+"]: Year "+(int32_t)testcase[i][0]+" Month "+(int32_t)testcase[i][1]+" Day "+
269 		                                    (int32_t)testcase[i][2]+" Hour "+(int32_t)testcase[i][3]+" Minutes "+(int32_t)testcase[i][4]+
270 		                                    " Seconds "+(int32_t)testcase[i][5]);
271 		gc->set((int32_t)testcase[i][0], (int32_t)testcase[i][1]-1, (int32_t)testcase[i][2], (int32_t)testcase[i][3], (int32_t)testcase[i][4], (int32_t)testcase[i][5]);
272                 CalendarAstronomer astro(gc->getTime(status));
273 		double expectedAge = (angle[i]*CalendarAstronomer::PI)/180;
274 		double got = astro.getMoonAge();
275 		//logln(testString);
276 		if(!(got>expectedAge-precision && got<expectedAge+precision)){
277 			errln((UnicodeString)"FAIL: expected " + expectedAge +
278 					" got " + got);
279 		}else{
280 			logln((UnicodeString)"PASS: expected " + expectedAge +
281 					" got " + got);
282 		}
283 	}
284 	close(status);
285 	ASSERT_OK(status);
286 }
287 
288 
289 // TODO: try finding next new moon after  07/28/1984 16:00 GMT
290 
291 
292 #endif
293 
294 
295 
296