Chris@1528: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@1528: 
Chris@1528: /*
Chris@1530:   Sonic Visualiser
Chris@1530:   An audio file viewer and annotation editor.
Chris@1530:   Centre for Digital Music, Queen Mary, University of London.
Chris@1528:     
Chris@1530:   This program is free software; you can redistribute it and/or
Chris@1530:   modify it under the terms of the GNU General Public License as
Chris@1530:   published by the Free Software Foundation; either version 2 of the
Chris@1530:   License, or (at your option) any later version.  See the file
Chris@1530:   COPYING included with this distribution for more information.
Chris@1528: */
Chris@1528: 
Chris@1528: #ifndef TEST_ZOOM_CONSTRAINTS_H
Chris@1528: #define TEST_ZOOM_CONSTRAINTS_H
Chris@1528: 
Chris@1528: #include "../PowerOfTwoZoomConstraint.h"
Chris@1528: #include "../PowerOfSqrtTwoZoomConstraint.h"
Chris@1552: #include "../RelativelyFineZoomConstraint.h"
Chris@1528: 
Chris@1528: #include <QObject>
Chris@1528: #include <QtTest>
Chris@1528: #include <QDir>
Chris@1528: 
Chris@1528: #include <iostream>
Chris@1528: 
Chris@1528: using namespace std;
Chris@1528: 
Chris@1528: class TestZoomConstraints : public QObject
Chris@1528: {
Chris@1528:     Q_OBJECT
Chris@1528: 
Chris@1552:     string roundingName(ZoomConstraint::RoundingDirection dir) {
Chris@1552:         switch (dir) {
Chris@1552:         case ZoomConstraint::RoundDown: return "RoundDown";
Chris@1552:         case ZoomConstraint::RoundUp: return "RoundUp";
Chris@1552:         case ZoomConstraint::RoundNearest: return "RoundNearest";
Chris@1552:         }
Chris@1552:         return "<?>";
Chris@1552:     }
Chris@1552:     
Chris@1552:     void compare(ZoomLevel zin,
Chris@1552:                  ZoomConstraint::RoundingDirection dir,
Chris@1552:                  ZoomLevel zobt,
Chris@1552:                  ZoomLevel zexp) {
Chris@1552:         if (zexp.level == 1) {
Chris@1552:             // A zoom level of "1 pixel per frame" is not considered
Chris@1552:             // canonical - it should be "1 frame per pixel"
Chris@1552:             zexp.zone = ZoomLevel::FramesPerPixel;
Chris@1552:         }
Chris@1552:         if (zobt == zexp) {
Chris@1552:             return;
Chris@1552:         } else {
Chris@1555:             std::cerr << "For input " << zin << " and rounding direction "
Chris@1555:                       << roundingName(dir)
Chris@1555:                       << ", expected output " << zexp << " but obtained "
Chris@1555:                       << zobt << std::endl;
Chris@1552:             QCOMPARE(zobt, zexp);
Chris@1552:         }
Chris@1552:     }
Chris@1552: 
Chris@1531:     void checkFpp(const ZoomConstraint &c,
Chris@1531:                   ZoomConstraint::RoundingDirection dir,
Chris@1531:                   int n,
Chris@1531:                   int expected) {
Chris@1552:         ZoomLevel zin(ZoomLevel::FramesPerPixel, n);
Chris@1552:         ZoomLevel zexp(ZoomLevel::FramesPerPixel, expected);
Chris@1552:         ZoomLevel zobt(c.getNearestZoomLevel(zin, dir));
Chris@1552:         compare(zin, dir, zobt, zexp);
Chris@1531:     }
Chris@1552: 
Chris@1552:     void checkPpf(const ZoomConstraint &c,
Chris@1552:                   ZoomConstraint::RoundingDirection dir,
Chris@1552:                   int n,
Chris@1552:                   int expected) {
Chris@1552:         ZoomLevel zin(ZoomLevel::PixelsPerFrame, n);
Chris@1552:         ZoomLevel zexp(ZoomLevel::PixelsPerFrame, expected);
Chris@1552:         ZoomLevel zobt(c.getNearestZoomLevel(zin, dir));
Chris@1552:         compare(zin, dir, zobt, zexp);
Chris@1552:     }
Chris@1552: 
Chris@1552:     void checkBoth(const ZoomConstraint &c,
Chris@1552:                    ZoomConstraint::RoundingDirection dir,
Chris@1552:                    int n,
Chris@1552:                    int expected) {
Chris@1552:         checkFpp(c, dir, n, expected);
Chris@1552:         checkPpf(c, dir, n, expected);
Chris@1552:     }
Chris@1552: 
Chris@1552:     void checkMaxMin(const ZoomConstraint &c,
Chris@1552:                      ZoomConstraint::RoundingDirection dir) {
Chris@1552:         auto max = c.getMaxZoomLevel();
Chris@1552:         compare(max, dir,
Chris@1552:                 c.getNearestZoomLevel(max, dir), max);
Chris@1552:         compare(max.incremented(), dir,
Chris@1552:                 c.getNearestZoomLevel(max.incremented(), dir), max);
Chris@1552:         auto min = c.getMinZoomLevel();
Chris@1552:         compare(min, dir,
Chris@1552:                 c.getNearestZoomLevel(min, dir), min);
Chris@1552:         compare(min.decremented(), dir,
Chris@1552:                 c.getNearestZoomLevel(min.decremented(), dir), min);
Chris@1552:     }
Chris@1552: 
Chris@1552:     const static ZoomConstraint::RoundingDirection up = ZoomConstraint::RoundUp;
Chris@1552:     const static ZoomConstraint::RoundingDirection down = ZoomConstraint::RoundDown;
Chris@1552:     const static ZoomConstraint::RoundingDirection nearest = ZoomConstraint::RoundNearest;
Chris@1552:                                                                          
Chris@1528: private slots:
Chris@1528:     void unconstrainedNearest() {
Chris@1528:         ZoomConstraint c;
Chris@1552:         checkBoth(c, nearest, 1, 1);
Chris@1552:         checkBoth(c, nearest, 2, 2);
Chris@1552:         checkBoth(c, nearest, 3, 3);
Chris@1552:         checkBoth(c, nearest, 4, 4);
Chris@1552:         checkBoth(c, nearest, 20, 20);
Chris@1552:         checkBoth(c, nearest, 32, 32);
Chris@1530:         auto max = c.getMaxZoomLevel();
Chris@1530:         QCOMPARE(c.getNearestZoomLevel(max), max);
Chris@1531:         QCOMPARE(c.getNearestZoomLevel(max.incremented()), max);
Chris@1528:     }
Chris@1528:     
Chris@1528:     void unconstrainedUp() {
Chris@1528:         ZoomConstraint c;
Chris@1552:         checkBoth(c, up, 1, 1);
Chris@1552:         checkBoth(c, up, 2, 2);
Chris@1552:         checkBoth(c, up, 3, 3);
Chris@1552:         checkBoth(c, up, 4, 4);
Chris@1552:         checkBoth(c, up, 20, 20);
Chris@1552:         checkBoth(c, up, 32, 32);
Chris@1530:         auto max = c.getMaxZoomLevel();
Chris@1552:         QCOMPARE(c.getNearestZoomLevel(max, up), max);
Chris@1552:         QCOMPARE(c.getNearestZoomLevel(max.incremented(), up), max);
Chris@1528:     }
Chris@1528:     
Chris@1528:     void unconstrainedDown() {
Chris@1528:         ZoomConstraint c;
Chris@1552:         checkBoth(c, down, 1, 1);
Chris@1552:         checkBoth(c, down, 2, 2);
Chris@1552:         checkBoth(c, down, 3, 3);
Chris@1552:         checkBoth(c, down, 4, 4);
Chris@1552:         checkBoth(c, down, 20, 20);
Chris@1552:         checkBoth(c, down, 32, 32);
Chris@1530:         auto max = c.getMaxZoomLevel();
Chris@1552:         QCOMPARE(c.getNearestZoomLevel(max, down), max);
Chris@1552:         QCOMPARE(c.getNearestZoomLevel(max.incremented(), down), max);
Chris@1528:     }
Chris@1528: 
Chris@1528:     void powerOfTwoNearest() {
Chris@1528:         PowerOfTwoZoomConstraint c;
Chris@1552:         checkBoth(c, nearest, 1, 1);
Chris@1552:         checkBoth(c, nearest, 2, 2);
Chris@1552:         checkBoth(c, nearest, 3, 2);
Chris@1552:         checkBoth(c, nearest, 4, 4);
Chris@1552:         checkBoth(c, nearest, 20, 16);
Chris@1552:         checkBoth(c, nearest, 23, 16);
Chris@1552:         checkBoth(c, nearest, 24, 16);
Chris@1552:         checkBoth(c, nearest, 25, 32);
Chris@1530:         auto max = c.getMaxZoomLevel();
Chris@1530:         QCOMPARE(c.getNearestZoomLevel(max), max);
Chris@1531:         QCOMPARE(c.getNearestZoomLevel(max.incremented()), max);
Chris@1528:     }
Chris@1528:     
Chris@1528:     void powerOfTwoUp() {
Chris@1528:         PowerOfTwoZoomConstraint c;
Chris@1552:         checkBoth(c, up, 1, 1);
Chris@1552:         checkBoth(c, up, 2, 2);
Chris@1552:         checkFpp(c, up, 3, 4);
Chris@1552:         checkPpf(c, up, 3, 2);
Chris@1552:         checkBoth(c, up, 4, 4);
Chris@1552:         checkFpp(c, up, 20, 32);
Chris@1552:         checkPpf(c, up, 20, 16);
Chris@1552:         checkBoth(c, up, 32, 32);
Chris@1552:         checkFpp(c, up, 33, 64);
Chris@1552:         checkPpf(c, up, 33, 32);
Chris@1552:         checkMaxMin(c, up);
Chris@1528:     }
Chris@1528:     
Chris@1528:     void powerOfTwoDown() {
Chris@1528:         PowerOfTwoZoomConstraint c;
Chris@1552:         checkBoth(c, down, 1, 1);
Chris@1552:         checkBoth(c, down, 2, 2);
Chris@1552:         checkFpp(c, down, 3, 2);
Chris@1552:         checkPpf(c, down, 3, 4);
Chris@1552:         checkBoth(c, down, 4, 4);
Chris@1552:         checkFpp(c, down, 20, 16);
Chris@1552:         checkPpf(c, down, 20, 32);
Chris@1552:         checkBoth(c, down, 32, 32);
Chris@1552:         checkFpp(c, down, 33, 32);
Chris@1552:         checkPpf(c, down, 33, 64);
Chris@1552:         checkMaxMin(c, down);
Chris@1528:     }
Chris@1528: 
Chris@1528:     void powerOfSqrtTwoNearest() {
Chris@1528:         PowerOfSqrtTwoZoomConstraint c;
Chris@1552:         checkBoth(c, nearest, 1, 1);
Chris@1552:         checkBoth(c, nearest, 2, 2);
Chris@1552:         checkBoth(c, nearest, 3, 2);
Chris@1552:         checkBoth(c, nearest, 4, 4);
Chris@1552:         checkBoth(c, nearest, 18, 16);
Chris@1552:         checkBoth(c, nearest, 19, 16);
Chris@1552:         checkBoth(c, nearest, 20, 22);
Chris@1552:         checkBoth(c, nearest, 23, 22);
Chris@1552:         checkBoth(c, nearest, 28, 32);
Chris@1528:         // PowerOfSqrtTwoZoomConstraint makes an effort to ensure
Chris@1528:         // bigger numbers get rounded to a multiple of something
Chris@1528:         // simple (64 or 90 depending on whether they are power-of-two
Chris@1528:         // or power-of-sqrt-two types)
Chris@1552:         checkBoth(c, nearest, 350, 360);
Chris@1552:         // The most extreme level available in ppf mode
Chris@1552:         // (getMinZoomLevel()) is currently 512, so these bigger
Chris@1552:         // numbers will only happen in fpp mode
Chris@1552:         checkFpp(c, nearest, 800, 720);
Chris@1552:         checkFpp(c, nearest, 1023, 1024);
Chris@1552:         checkFpp(c, nearest, 1024, 1024);
Chris@1552:         checkFpp(c, nearest, 1024, 1024);
Chris@1552:         checkFpp(c, nearest, 1025, 1024);
Chris@1552:         checkPpf(c, nearest, 800, 512);
Chris@1552:         checkPpf(c, nearest, 1025, 512);
Chris@1552:         checkMaxMin(c, nearest);
Chris@1528:     }
Chris@1528:     
Chris@1528:     void powerOfSqrtTwoUp() {
Chris@1528:         PowerOfSqrtTwoZoomConstraint c;
Chris@1552:         checkBoth(c, up, 1, 1);
Chris@1552:         checkBoth(c, up, 2, 2);
Chris@1552:         checkFpp(c, up, 3, 4);
Chris@1552:         checkPpf(c, up, 3, 2);
Chris@1552:         checkBoth(c, up, 4, 4);
Chris@1552:         checkFpp(c, up, 18, 22);
Chris@1552:         checkPpf(c, up, 18, 16);
Chris@1552:         checkBoth(c, up, 22, 22);
Chris@1552:         checkFpp(c, up, 23, 32);
Chris@1552:         checkPpf(c, up, 23, 22);
Chris@1552:         // see comments above
Chris@1552:         checkFpp(c, up, 800, 1024);
Chris@1552:         checkFpp(c, up, 1023, 1024);
Chris@1552:         checkFpp(c, up, 1024, 1024);
Chris@1552:         checkFpp(c, up, 1025, 1440);
Chris@1552:         checkPpf(c, up, 300, 256);
Chris@1552:         checkPpf(c, up, 800, 512);
Chris@1552:         checkPpf(c, up, 1600, 512);
Chris@1552:         checkMaxMin(c, up);
Chris@1528:     }
Chris@1528:     
Chris@1528:     void powerOfSqrtTwoDown() {
Chris@1528:         PowerOfSqrtTwoZoomConstraint c;
Chris@1552:         checkBoth(c, down, 1, 1);
Chris@1552:         checkBoth(c, down, 2, 2);
Chris@1552:         checkFpp(c, down, 3, 2);
Chris@1552:         checkPpf(c, down, 3, 4);
Chris@1552:         checkBoth(c, down, 4, 4);
Chris@1552:         checkFpp(c, down, 18, 16);
Chris@1552:         checkPpf(c, down, 18, 22);
Chris@1552:         checkBoth(c, down, 22, 22);
Chris@1552:         checkFpp(c, down, 23, 22);
Chris@1552:         checkPpf(c, down, 23, 32);
Chris@1552:         // see comments above
Chris@1552:         checkFpp(c, down, 800, 720);
Chris@1552:         checkFpp(c, down, 1023, 720);
Chris@1552:         checkFpp(c, down, 1024, 1024);
Chris@1552:         checkFpp(c, down, 1025, 1024);
Chris@1552:         checkPpf(c, down, 300, 360);
Chris@1552:         checkPpf(c, down, 800, 512);
Chris@1552:         checkPpf(c, down, 1600, 512);
Chris@1552:         checkMaxMin(c, down);
Chris@1552:     }
Chris@1552: 
Chris@1552:     void relativelyFineNearest() {
Chris@1552:         RelativelyFineZoomConstraint c;
Chris@1552:         checkBoth(c, nearest, 1, 1);
Chris@1552:         checkBoth(c, nearest, 2, 2);
Chris@1552:         checkBoth(c, nearest, 3, 3);
Chris@1552:         checkBoth(c, nearest, 4, 4);
Chris@1552:         checkBoth(c, nearest, 20, 20);
Chris@1552:         checkBoth(c, nearest, 33, 32);
Chris@1552:         checkBoth(c, nearest, 59, 56);
Chris@1552:         checkBoth(c, nearest, 69, 72);
Chris@1552:         checkBoth(c, nearest, 121, 128);
Chris@1552:         checkMaxMin(c, nearest);
Chris@1552:     }
Chris@1552:     
Chris@1552:     void relativelyFineUp() {
Chris@1552:         RelativelyFineZoomConstraint c;
Chris@1552:         checkBoth(c, up, 1, 1);
Chris@1552:         checkBoth(c, up, 2, 2);
Chris@1552:         checkBoth(c, up, 3, 3);
Chris@1552:         checkBoth(c, up, 4, 4);
Chris@1552:         checkBoth(c, up, 20, 20);
Chris@1552:         checkFpp(c, up, 33, 36);
Chris@1552:         checkPpf(c, up, 33, 32);
Chris@1552:         checkFpp(c, up, 59, 64);
Chris@1552:         checkPpf(c, up, 59, 56);
Chris@1552:         checkFpp(c, up, 69, 72);
Chris@1552:         checkPpf(c, up, 69, 64);
Chris@1552:         checkFpp(c, up, 121, 128);
Chris@1552:         checkPpf(c, up, 121, 112);
Chris@1552:         checkMaxMin(c, up);
Chris@1552:     }
Chris@1552:     
Chris@1552:     void relativelyFineDown() {
Chris@1552:         RelativelyFineZoomConstraint c;
Chris@1552:         checkBoth(c, down, 1, 1);
Chris@1552:         checkBoth(c, down, 2, 2);
Chris@1552:         checkBoth(c, down, 3, 3);
Chris@1552:         checkBoth(c, down, 4, 4);
Chris@1552:         checkBoth(c, down, 20, 20);
Chris@1552:         checkFpp(c, down, 33, 32);
Chris@1552:         checkPpf(c, down, 33, 36);
Chris@1552:         checkFpp(c, down, 59, 56);
Chris@1552:         checkPpf(c, down, 59, 64);
Chris@1552:         checkFpp(c, down, 69, 64);
Chris@1552:         checkPpf(c, down, 69, 72);
Chris@1552:         checkFpp(c, down, 121, 112);
Chris@1552:         checkPpf(c, down, 121, 128);
Chris@1552:         checkMaxMin(c, down);
Chris@1528:     }
Chris@1528: };
Chris@1528: 
Chris@1528: #endif
Chris@1528: