Skip to content

Commit

Permalink
Added finalization review for dives comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
jirkapok committed Mar 14, 2024
1 parent 4da37db commit c3f0909
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 5 deletions.
7 changes: 3 additions & 4 deletions doc/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@ Following list of features and improvements ordered by priority is under develop
* https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Offline_Service_workers
* https://developers.google.com/codelabs/pwa-training/pwa03--going-offline#1)
* Allow user to compare multiple plans side by side
* I want compare consequences of emergency ascent
* I want to plan a dive and choose from two following plans or two independent plans
* Add tests
* Fix remaining TODOs in the Diff
* UI Tweaks
* Read only fields should be distinguish able
* Profile:
* Waypoints table: add switch in case user is switching to tank with the same gas
* Gas switch is not present in shortened waypoints list
* Recommended and recreational buttons still calculated even with invalid altitude (or any other control not in the same form)
* Add limitation for shallow dives below 10 meters, that max. duration is limited to no deco limit and longer dives are saturation dives and this calculator does not work for them.
* Add warnings to gas properties calc for properties exceeding recommended maximum
* Extend application settings:
* Define custom maximum gas density
* Custom diver stress sac rate ratio
Expand All @@ -52,6 +50,7 @@ Following list of features and improvements ordered by priority is under develop
* TRIMIX support
* Add air breaks
* Add CCR support
* UI Tweaks: Read only fields should be distinguish able
* Add undo/redo to all pages
* Add export of the plan to pdf
* Import/Export dive to compare from well known file format see also <https://www.npmjs.com/package/xml-js>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('DiveResultsTableDifferenceComponent', () => {
fixture.detectChanges();
});

// TODO reorganize component methods to compare service
it('should create', () => {
expect(component).toBeTruthy();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@ describe('DiffGasConsumedComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});

// TODO extract getMixedTanks to separate service, see also methods in dif-gas-consumed-tank-chart
it('Creates compared gases', () => {
expect(component.getMixedTanks).not.toBeNull();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ describe('DiffTabsButtonComponent', () => {
fixture.detectChanges();
});

// TODO move subscribed events to selected model
// TODO merge with diff-tabs component
it('should create', () => {
expect(component).toBeTruthy();
});
Expand Down
2 changes: 1 addition & 1 deletion projects/planner/src/app/mainmenu/mainmenu.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
<a class="dropdown-item" (click)="loadDefaults()">Reload defaults</a>
</div>
</li>
<a class="nav-link" href="{{urls.standardGases}}" target="_blank">Standard gases</a>
<a class="nav-link" routerLink="/diff">Compare dives</a>
<a class="nav-link" href="{{urls.standardGases}}" target="_blank">Standard gases</a>
<a class="nav-link" href="{{urls.helpUrl}}" target="_blank">Help/Learn</a>
<a class="nav-link" routerLink="/about">About</a>
</ul>
Expand Down
155 changes: 155 additions & 0 deletions projects/planner/src/app/shared/profileCompoarator.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { inject, TestBed } from '@angular/core/testing';
import { DiveSchedules } from './dive.schedules';
import { ProfileComparatorService } from './profileComparatorService';
import { ReloadDispatcher } from './reloadDispatcher';
import { UnitConversion } from './UnitConversion';
import { WayPoint } from './models';
import { ConsumptionByMix, IConsumedMix, Segment, StandardGases, Tank } from 'scuba-physics';

describe('ProfileComparison service', () => {
let sut: ProfileComparatorService;
let schedules: DiveSchedules;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [],
imports: [],
providers: [
ProfileComparatorService, UnitConversion,
ReloadDispatcher, DiveSchedules,
]
}).compileComponents();
});

beforeEach(() => {
sut = TestBed.inject(ProfileComparatorService);
schedules = TestBed.inject(DiveSchedules);
});

it('Has default dives', () => {
expect(sut.profileA).toEqual(schedules.dives[0]);
expect(sut.profileB).toEqual(schedules.dives[0]);
});

it('Has only one profile', () => {
expect(sut.hasTwoProfiles()).toBeFalsy();
});

// TODO remove hasTwoProfiles or use it
// change it to get property and all other properties in the service
it('Has two profiles', () => {
schedules.add();
expect(sut.hasTwoProfiles()).toBeTruthy();
});

it('Total duration of one dive', inject([UnitConversion], (units: UnitConversion) => {
schedules.selected.diveResult.wayPoints = [
WayPoint.fromSegment(units, new Segment(0,0, StandardGases.air, 600))
];

expect(sut.totalDuration).toEqual(600);
}));

it('Total duration Profile B dive', inject([UnitConversion], (units: UnitConversion) => {
schedules.add();
schedules.dives[0].diveResult.wayPoints = [
WayPoint.fromSegment(units, new Segment(0,0, StandardGases.air, 500))
];

schedules.dives[1].diveResult.wayPoints = [
WayPoint.fromSegment(units, new Segment(0,0, StandardGases.air, 700))
];
// TODO rename appendProfileToProfileComparison to selectProfile
sut.appendProfileToProfileComparison(1);

expect(sut.totalDuration).toEqual(700);
}));

// TODO rename to Consumption profileACombinedTanks, profileBCombinedTanks
describe('Tanks combined consumption', () => {
let combineMethod: jasmine.Spy<(tanks: Tank[]) => IConsumedMix[]>;

beforeEach(() => {
schedules.add();
schedules.dives[0].tanksService.tankData[0].consumed = 50;
schedules.dives[1].tanksService.tankData[0].consumed = 100;
sut.appendProfileToProfileComparison(1);
combineMethod = spyOn(ConsumptionByMix, 'combine')
.and.callThrough();
});

it('profileACombinedTanks call combined consumption for Profile A', () => {
const _ = sut.profileACombinedTanks;
expect(combineMethod).toHaveBeenCalledWith(sut.profileA.tanksService.tankData);
});

it('profileBCombinedTanks call combined consumption for Profile B', () => {
const _ = sut.profileBCombinedTanks;
expect(combineMethod).toHaveBeenCalledWith(sut.profileB.tanksService.tankData);
});
});

describe('Handles only calculated profiles', () => {
// TODO areProfilesCalculated change to property
// TODO switch waitUntilProfilesCalculated to use events from Dispatcher the drawing components
it('Waits until profiles are calculated', async() => {
let eventReceived = false;
sut.profileAResults.showStillRunning();

setTimeout(() => {
sut.profileAResults.profileFinished();
}, 110); // more than the service waits

await sut.waitUntilProfilesCalculated().then(() => {
eventReceived = true;
});

expect(eventReceived).toBeTruthy();
});

it('By default Not calculated profiles', () => {
expect(sut.areProfilesCalculated()).toBeFalsy();
});

it('Profiles are already calculated', () => {
// TODO distinguish profile calculated, consumption and diveInfo
sut.profileAResults.profileFinished();
sut.profileBResults.profileFinished();
expect(sut.areProfilesCalculated()).toBeTruthy();
});
});

describe('Select new profile', () => {
const expectedA = 2;
const expectedB = 1;
let newProfileA = -1; // set to non existing index
let newProfileB = -1;

beforeEach(() => {
schedules.add();
schedules.add();

// TODO rename to ProfileAChanged and dont create new one, but initialize in constructor
sut.profileAIndex.subscribe((newIndex: number) => newProfileA = newIndex);
sut.profileBIndex.subscribe((newIndex: number) => newProfileB = newIndex);

// TODO remove appendProfileToProfileComparison method return value
sut.appendProfileToProfileComparison(expectedA);
sut.appendProfileToProfileComparison(expectedB);
});

it('Selects Profile', () => {
expect(sut.profileA).toEqual(schedules.dives[expectedA]);
expect(sut.profileB).toEqual(schedules.dives[expectedB]);
});

it('Profile A change event received', () => {
expect(newProfileA).toEqual(expectedA);
});

it('Profile B change event received', () => {
expect(newProfileB).toEqual(expectedB);
});
});
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { TestBed } from '@angular/core/testing';
import { WaypointsDifferenceService } from './waypoints-difference.service';
import { ProfileComparatorService } from './profileComparatorService';
import { DiveSchedules } from './dive.schedules';
import { UnitConversion } from './UnitConversion';
import { ReloadDispatcher } from './reloadDispatcher';

fdescribe('WayPoints Difference Service', () => {
let sut: WaypointsDifferenceService;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [],
providers: [
WaypointsDifferenceService, ProfileComparatorService,
DiveSchedules, UnitConversion, ReloadDispatcher
],
imports: []
}).compileComponents();
});

beforeEach(() => {
sut = TestBed.inject(WaypointsDifferenceService);
});

// TODO add more real tests on diff of two dive waypoints
it('No errors comparing waypoints', () => {
// TODO rename to difference, refactor to property
const diff = sut.getRows();
expect(diff).not.toBeNull();
});
});

0 comments on commit c3f0909

Please sign in to comment.