SunStudyTestJson.RootTest LoadTestData(string testFileName)
        {
            string testFilePath = Path.Combine(Application.dataPath, "Tests", "Editor", "Data", testFileName);

            if (!File.Exists(testFilePath))
            {
                string[] guids = AssetDatabase.FindAssets(Path.GetFileNameWithoutExtension(testFileName));
                if (guids.Length > 0)
                {
                    foreach (var guid in guids)
                    {
                        string path = AssetDatabase.GUIDToAssetPath(guid);
                        if (File.Exists(path))
                        {
                            testFilePath = path;
                            break;
                        }
                    }
                }
            }

            string json = File.ReadAllText(testFilePath);

            SunStudyTestJson.RootTest testData = JsonUtility.FromJson <SunStudyTestJson.RootTest>(json);

            return(testData);
        }
        protected void ExecuteSolarCycleTest(float errorThresholdMinutes, string testJsonFileName)
        {
            SunStudyTestJson.RootTest testData = LoadTestData(testJsonFileName);

            var geoCoordinates  = Tuple.Create <float, float>(testData.latitude, testData.longitude);
            int utcOffsetHour   = (int)testData.utcOffset;
            int utcOffsetMinute = (int)((testData.utcOffset - utcOffsetHour) * 60f);
            var offset          = new TimeSpan(utcOffsetHour, utcOffsetMinute, 0);

            foreach (var value in testData.values)
            {
                if (value.timeH != 0)
                {
                    // For solar tests, we can test only one hour entry per day since we are testing sunrise and sunset times.
                    continue;
                }

                double sunriseCheck        = value.localSunriseHourFraction;
                int    sunriseCheckHour    = (int)sunriseCheck;
                double sunriseCheckMinutes = sunriseCheckHour * 60.0 + (sunriseCheck - sunriseCheckHour);

                double sunsetCheck        = value.localSunsetHourFraction;
                int    sunsetCheckHour    = (int)sunsetCheck;
                double sunsetCheckMinutes = sunsetCheckHour * 60.0 + (sunsetCheck - sunsetCheckHour);

                var solarCheckDate = new DateTimeOffset(value.dateY, value.dateM, value.dateD, 0, 0, 0, offset);
                (double julianSunrise, double julianSunset, double transit) = SunStudy.GetJulianDatesForSunriseAndSunset(solarCheckDate, geoCoordinates.Item1, geoCoordinates.Item2);

                DateTimeOffset sunriseDateTime = SunStudy.MakeDateTimeOffsetWithJulianDateTimeFraction(julianSunrise, solarCheckDate);
                DateTimeOffset sunsetDateTime  = SunStudy.MakeDateTimeOffsetWithJulianDateTimeFraction(julianSunset, solarCheckDate);

                double sunriseTestMinutes = sunriseDateTime.Hour * 60.0 + sunriseDateTime.Minute;
                double sunsetTestMinutes  = sunsetDateTime.Hour * 60.0 + sunsetDateTime.Minute;

                Assert.AreEqual(sunriseCheckMinutes, sunriseTestMinutes, errorThresholdMinutes, $"Sunrise time not equal with {errorThresholdMinutes} minutes accuracy: JD Sunrise = {julianSunrise}, SPA Check JD value = {sunriseCheck}");
                Assert.AreEqual(sunsetCheckMinutes, sunsetTestMinutes, errorThresholdMinutes, $"Sunset time not equal with {errorThresholdMinutes} minutes accuracy: JD Sunrise = {julianSunrise}, SPA Check JD value = {sunsetCheck}");
            }
        }
        void ExecuteTest(float errorThreshold, string testJsonFileName, bool testAzimuth)
        {
            SunStudyTestJson.RootTest testData = LoadTestData(testJsonFileName);

            var geoCoordinates  = Tuple.Create <float, float>(testData.latitude, testData.longitude);
            int utcOffsetHour   = (int)testData.utcOffset;
            int utcOffsetMinute = (int)((testData.utcOffset - utcOffsetHour) * 60f);
            var offset          = new TimeSpan(utcOffsetHour, utcOffsetMinute, 0);

            var dateTimeInputs  = new List <DateTimeOffset>();
            var expectedOutputs = new List <Tuple <float, float> >();

            foreach (var test in testData.values)
            {
                dateTimeInputs.Add(new DateTimeOffset(test.dateY, test.dateM, test.dateD, test.timeH, test.timeM, test.timeS, offset));
                expectedOutputs.Add(Tuple.Create <float, float>(test.azimuth, test.elevation));
            }

            Assert.IsTrue(dateTimeInputs.Count == expectedOutputs.Count);

            for (int testCaseIndex = 0; testCaseIndex < dateTimeInputs.Count; ++testCaseIndex)
            {
                DateTimeOffset dateTime       = dateTimeInputs[testCaseIndex];
                var            expectedResult = expectedOutputs[testCaseIndex];
                (float resultAzimuth, float resultAltitude) = SunStudy.CalculateSunPosition(dateTime, geoCoordinates.Item1, geoCoordinates.Item2);

                if (testAzimuth)
                {
                    Assert.AreEqual(expectedResult.Item1, resultAzimuth, errorThreshold, $"Azimuth not equal with {errorThreshold} accuracy at Hour {dateTime.Hour}.");
                }
                else
                {
                    Assert.AreEqual(expectedResult.Item2, resultAltitude, errorThreshold, $"Elevation not equal with {errorThreshold} accuracy at Hour {dateTime.Hour}.");
                }
            }
        }