diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java index a0cc9e970..0a68d0546 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/CalorieUtils.java @@ -15,6 +15,8 @@ */ package com.google.android.apps.mytracks.util; +import com.google.common.annotations.VisibleForTesting; + import android.location.Location; /** @@ -40,7 +42,8 @@ public class CalorieUtils { /** * Changes 4.5 miles per hour to meters per minutes. */ - private static final double CRTICAL_SPEED_RUNNING = 4.5 * UnitConversions.MI_TO_KM * 1000 / 60; + @VisibleForTesting + static final double CRTICAL_SPEED_RUNNING = 4.5 * UnitConversions.MI_TO_KM * 1000 / 60; public enum ActivityType { CYCLING, FOOT @@ -55,7 +58,8 @@ public class CalorieUtils { * @param grade * @return the VO2 value in ml/kg/min */ - private static double calculateWalkingVO2(double speed, double grade) { + @VisibleForTesting + static double calculateWalkingVO2(double speed, double grade) { /* * 0.1 means oxygen cost per meter of moving each kilogram (kg) of body * weight while walking (horizontally). 1.8 means oxygen cost per meter of @@ -73,7 +77,8 @@ public class CalorieUtils { * @param grade * @return the VO2 value in ml/kg/min */ - private static double calculateRunningVO2(double speed, double grade) { + @VisibleForTesting + static double calculateRunningVO2(double speed, double grade) { /* * 0.2 means oxygen cost per meter of moving each kg of body weight while @@ -105,8 +110,8 @@ public class CalorieUtils { * @param timeUsed how many times used in second * @return the power value watts(Joule/second) */ - private static double calculateCyclingCalories(double speed, double grade, int weight, - double timeUsed) { + @VisibleForTesting + static double calculateCyclingCalories(double speed, double grade, int weight, double timeUsed) { // Get the Power. double power = 9.8 * weight * speed * (0.0053 + grade) + 0.185 * (speed * speed * speed); // Get the calories. @@ -122,8 +127,8 @@ public class CalorieUtils { * @param weight the weight of user * @return the calories expenditure between the start and stop location */ - private static double calculateExpenditureCycling(Location start, Location stop, double grade, - int weight) { + @VisibleForTesting + static double calculateExpenditureCycling(Location start, Location stop, double grade, int weight) { // Seconds. double time = (double) (stop.getTime() - start.getTime()) / 1000; // Meter per second. @@ -144,22 +149,14 @@ public class CalorieUtils { * @param weight the weight of user * @return the calories expenditure between the start and stop location */ - private static double calculateExpenditureFoot(Location start, Location stop, double grade, - int weight) { - // Seconds. - double time = (double) (stop.getTime() - start.getTime()) / 1000; + @VisibleForTesting + static double calculateExpenditureFoot(Location start, Location stop, double grade, int weight) { // Meter per minute. double speed = (start.getSpeed() + stop.getSpeed()) * 60 / 2; - double VO2 = 0; - if (grade < 0) { - grade = 0; - } - - if (speed > CRTICAL_SPEED_RUNNING) { - VO2 = calculateRunningVO2(speed, grade); - } else { - VO2 = calculateWalkingVO2(speed, grade); - } + // Get VO2 + double VO2 = getVO2(speed, grade); + // Seconds. + double time = (double) (stop.getTime() - start.getTime()) / 1000; // Change mL/kg/min to mL/kg. double VO2All = VO2 * time / 60; // Change mL/kg to L/kg. @@ -168,6 +165,29 @@ public class CalorieUtils { return VO2All * weight * VO2H_TO_KCAL; } + /** + * Gets the VO2 value. + * + * @param start the start location + * @param stop the stop location + * @param grade the grade to calculate + * @return the VO2 value + */ + @VisibleForTesting + static double getVO2(double speed, double grade) { + if (grade < 0) { + grade = 0; + } + + double VO2 = 0; + if (speed > CRTICAL_SPEED_RUNNING) { + VO2 = calculateRunningVO2(speed, grade); + } else { + VO2 = calculateWalkingVO2(speed, grade); + } + return VO2; + } + /** * Calculates the calories expenditure between two locations. * diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/util/CalorieUtilsTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/util/CalorieUtilsTest.java new file mode 100644 index 000000000..fb24459fd --- /dev/null +++ b/MyTracksTest/src/com/google/android/apps/mytracks/util/CalorieUtilsTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks.util; + +import android.location.Location; +import android.location.LocationManager; + +import junit.framework.TestCase; + +/** + * A unit test for {@link CalorieUtils}. + * + * @author youtaol + */ +public class CalorieUtilsTest extends TestCase { + + Location start = new Location(LocationManager.GPS_PROVIDER); + Location stop = new Location(LocationManager.GPS_PROVIDER); + private double grade = 10; + private int weight = 20; + + @Override + protected void setUp() throws Exception { + super.setUp(); + // Make the time interval is not 0. + stop.setTime(start.getTime() + 1000); + } + + /** + * Checks using foot calculation equation. + */ + public void testGetCalories_foot() { + double actual = CalorieUtils.getCalories(start, stop, grade, weight, + CalorieUtils.ActivityType.FOOT); + double expected = CalorieUtils.calculateExpenditureFoot(start, stop, grade, weight); + assertEquals(expected, actual); + } + + /** + * Checks whether using foot calculation equation while grade is negative. + */ + public void testGetCalories_footNegativeGrade() { + double actual = CalorieUtils.getCalories(start, stop, -5, weight, + CalorieUtils.ActivityType.FOOT); + double expected = CalorieUtils.calculateExpenditureFoot(start, stop, 0, weight); + assertEquals(expected, actual); + } + + /** + * Checks using cycling calculation equation. + */ + public void testGetCalories_cycling() { + double actual = CalorieUtils.getCalories(start, stop, grade, weight, + CalorieUtils.ActivityType.CYCLING); + double expected = CalorieUtils.calculateExpenditureCycling(start, stop, grade, weight); + assertEquals(expected, actual); + } + + /** + * Checks using running VO2 equation. + */ + public void testGetVO2_running() { + double actual = CalorieUtils.getVO2(CalorieUtils.CRTICAL_SPEED_RUNNING * 2, grade); + double expected = CalorieUtils.calculateRunningVO2(CalorieUtils.CRTICAL_SPEED_RUNNING * 2, + grade); + assertEquals(expected, actual); + } + + /** + * Checks using walking VO2 equation. + */ + public void testGetVO2_walking() { + double actual = CalorieUtils.getVO2(CalorieUtils.CRTICAL_SPEED_RUNNING / 2, grade); + double expected = CalorieUtils.calculateWalkingVO2(CalorieUtils.CRTICAL_SPEED_RUNNING / 2, + grade); + assertEquals(expected, actual); + } + +}