From 58f441c35384e505a7aff050575aa474659b39bb Mon Sep 17 00:00:00 2001 From: David Byers <david.byers@liu.se> Date: Tue, 21 Jul 2020 20:15:12 +0200 Subject: [PATCH] Updated documentation. --- CHANGELOG | 32 +++++++ README.md | 118 +++++++---------------- olc.el | 117 +++++++++++++++-------- olc.texi | 248 ++++++++++++++++++++++++++++++++++++++++++++++++ test/olctest.el | 60 +++++++++--- 5 files changed, 437 insertions(+), 138 deletions(-) create mode 100644 CHANGELOG create mode 100644 olc.texi diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..deef8f4 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,32 @@ +2020-07-21 David Byers <david.byers@liu.se> + + Wrote texinfo documentation: + * olc.el (olc-parse-length): Removed. + Updated documentation comment. + (olc-decode): Updated docstring. + (olc-encode): Updated docstring. + (olc-recover): Updated docstring. + (olc-shorten): Updated docstring. + (olc-recover-string): Updated docstring. + + * olc.texi: New file. + + Implement shorten: + * test/olctest.el (olctest-decode): Change olc-code-length to + olc-code-precision. + (olctest-shortcodes): Implement shorten tests. + (olctest-localtests): New function. + + * olc.el + (olc-code-precision): New function. + (olc-latitude-precision): Change ffloor to floor. + (olc-shorten-error): New error. + (olc-clip-latitude): New function. + (olc-normalize-latitude): Use it. Convert to subst. Renamed length + to len to reduce confusion. + (olc-normalize-longitude): Convert to subst. + (olc-valid-char): Reimplemented missing function. + (olc-shorten): New function. + (olc-recover): Use olc-clip-latitude, not normalize. + + diff --git a/README.md b/README.md index 13316d5..9868235 100644 --- a/README.md +++ b/README.md @@ -20,98 +20,50 @@ implements all the required and most of the optional features in the standard, and passes the test cases published in the open location code github repository (see above). -### Data structures +The complete documentation is available in texinfo format. The +following examples may be helpful. -#### OLC Area +## Examples -An OLC is the area represented by an open location code. All fields -are read-only once the object has been created. +### Encoding -`(olc-area-create :latlo LATLO :lonlo LONLO :lathi LATHI :lonhi LONHI)` -: Creates an OLC area with southwest corner `LATLO`,`LONLO` and - northeast corner `LATHI`,`LONHI`. +```` +(olc-encode 58.397813 15.576063 11) +"9FCQ9HXG+4CG" +```` -`(olc-area-p OBJ)` -: Return non-nil if `OBJ` is an OLC area. +### Decoding -`(olc-area-latlo AREA)` -`(olc-area-lonlo AREA)` -`(olc-area-lathi AREA)` -`(olc-area-lonhi AREA)` -: Get the south, west, north, and east coordinates of the area, - respectively. +```` +(olc-decode "9FCQ9HXG+4CG") +#s(olc-area 58.397800000000004 15.5760625 58.397825000000005 15.57609375) +(olc-area-lat (olc-decode "9FCQ9HXG+4CG")) +58.3978125 +(olc-area-lon (olc-decode "9FCQ9HXG+4CG")) +```` -`(olc-area-lat AREA)` -`(olc-area-lon AREA)` -: Get the center latitude and longitude of the area, respectively. +### Shortening -#### OLC Parse +```` +(olc-shorten "9C3W9QCJ+2VX" 51.3701125 -1.217765625) +"+2VX" +(olc-shorten "9C3W9QCJ+2VX" 51.3701125 -1.217765625 4) +"9QCJ+2VX" +```` -The OLC parse is a structure mainly used internally. Unless you call -`olc-parse-code` you will probably never see one. +### Recovery -`(olc-parse-create &keys pairs grid short prec code)` -: Creates an OLC parse structure. Don't call this: use - `olc-parse-code` instead. +Recovery using latitude and longitude as reference: -`(olc-parse-pairs PARSE)` -: Returns the list of parsed pairs from the code (pairs are before the - plus sign and the first two characters after, if present). +```` +(olc-recover "+2VX" 51.3701125 -1.217765625) +"9C3W9QCJ+2VX" +```` -`(olc-parse-grid PARSE)` -: Returns the list of parsed grid digits from the code (the optional - digits that follow the last pair). +Recovery using a geographical reference (requires `requests` and uses +the OpenStreetMap API): -`(olc-parse-short PARSE)` -: Non-nil if the parsed code was shortened. - -`(olc-parse-precision PARSE)` -: Precision of the parsed code. Padded codes can have precisions lower - than 8. All other full and all short codes have precision of at - least 8 (although, don't cound on short codes always having - precision 8 or more). - -`(olc-parse-code PARSE)` -: The parsed code. - - -### Functions - -`(olc-encode lat lon len)` -: Encode a latitude LAT, longitude LON, into an open location code of - length LEN. All arguments will be clipped to acceptable values. - -`(olc-decode code)` -: Decode a code CODE. Returns an OLC area (see above). - -`(olc-recover code lat lon &optional format)` -: Recover the closest point to coordinates `LAT` and `LON` with a code - that can be shortened to `CODE`. If FORMAT is `'latlon`, then the - center of the recovered area `(LAT . LON)` is returned. If FORMAT is - `'area` (or any other value), the returned value is an full open - location code. - -`(olc-recover-string arg1 &optional arg2 arg3)` -: Recover a shortened code *without* the reference latitude and - longitude. When called with one argument, it must be a string - consisting of a shortened open location code followed by whitespace - and a geographical location. When called with two strings, the first - must be a shortened open location code and the second if the - geographical location. Optionally, the last argument in either case - can be a symbol indicating the format of the return value (see - `olc-recover`, above). This function requires the `request` package - to be installed, and uses the Open Streetmap API to convert the - geographical reference to coordinates. Please make sure you follow - the acceptable use policy for the API (e.g., one request per second, - tops, allowed). - -`(olc-is-valid CODE)` -: Returns non-nil if `CODE` is a valid open location code. - -`(olc-is-short CODE)` -: Returns non-nil if `CODE` is a valid short location code. Returns - nil for valid short and for invalid codes. - -`(olc-is-full CODE)` -: Returns non-nil if `CODE` is a valid full open location code. - Returns nil for valid long and for invalid codes. +```` +(olc-recover-string "M24Q+89 Mutitjulu") +"5Q6HM24Q+89" +```` diff --git a/olc.el b/olc.el index be38e8e..64715dc 100644 --- a/olc.el +++ b/olc.el @@ -19,31 +19,20 @@ ;;; ======================================================================== ;;; This program provides basic open location code support in emacs ;;; lisp. The support for recovering shortened codes depends on the -;;; request library and uses Open Streetmap; please check the terms of +;;; request library and uses OpenStreetMap; please check the terms of ;;; use for the service to ensure that you remain compliant. ;;; ;;; All methods required by the open location code specification are ;;; provided in some form. The implementation passed the tests present ;;; in the open location code github repository at the time of writing ;;; almost cleanly -- there are some minor rounding issues in decode. -;;; -;;; olc-encode encodes latitude and longitude to any length code. -;;; olc-decode decodes any length code (without reference location). -;;; olc-recover recovers shortened codes -;;; -;;; olc-is-valid checks for valid codes (long or short). -;;; olc-is-short checks for valid short codes. -;;; olc-is-full checks for valid full codes. -;;; olc-valid-digits checks for valid digits. -;;; -;;; There is no support for shortening codes. ;;; ======================================================================== ;; This is me being dragged kicking and screaming into the 21st -;; century because the alternative is to include my own structured -;; data code -- which would be overkill -- or do it manually -- which is -;; a pain in the read end. So cl-lib it is. +;; century because the alternative is to cl-lib is to include my own +;; structured data code (which would be overkill) or do it manually +;; (which is a pain in the backside). So cl-lib it is. (require 'cl-lib) (require 'request nil t) @@ -57,6 +46,7 @@ (define-error 'olc-parse-error "Parse error in open location code" 'olc-error) (define-error 'olc-decode-error "Error decoding open location code" 'olc-error) (define-error 'olc-encode-error "Error encoding open location code" 'olc-error) +(define-error 'olc-shorten-error "Error shortening open location code" 'olc-error) ;; ======================================================================== ;; Mapping of digits to base 20 values @@ -93,11 +83,6 @@ (short nil :read-only t) (precision nil :read-only t)) -(defsubst olc-parse-length (parse) - "Get length from a parsed open location code PARSE." - (+ (* 2 (length (olc-parse-pairs parse))) - (length (olc-parse-grid parse)))) - (cl-defstruct (olc-area (:copier nil) (:constructor olc-area-create)) (latlo nil :read-only t) @@ -118,6 +103,10 @@ ;; (Mostly) internal functions ;; ======================================================================== +(defmacro olc-valid-char (char) + "Check if CHAR is a valid OLC digit." + `(assq ,char olc-digit-mapping)) + (defmacro olc-transform-error (spec &rest body) "Catch some errors and throw others." (declare (indent 1)) @@ -125,15 +114,19 @@ ,@body (,(elt spec 0) (signal ',(elt spec 1) (list ,@(cddr spec)))))) -(defun olc-normalize-latitude (lat length) +(defsubst olc-clip-latitude (lat) + "Clip LAT to -90,90" + (max -90 (min 90 lat))) + +(defsubst olc-normalize-latitude (lat len) "Normalize latitude LAT." - (setq lat (max -90 (min 90 lat))) + (setq lat (olc-clip-latitude lat)) (when (= lat 90.0) - (setq lat (- lat (/ (olc-latitude-precision length) 2.0)))) + (setq lat (- lat (/ (olc-latitude-precision len) 2.0)))) lat) -(defun olc-normalize-longitude (lon) +(defsubst olc-normalize-longitude (lon) "Normalize longitude LON." (while (< lon -180) (setq lon (+ lon 360))) (while (>= lon 180) (setq lon (- lon 360))) @@ -142,7 +135,7 @@ (defun olc-latitude-precision (len) "Compute latitude precision in code of length LEN." (if (<= len 10) - (expt 20 (- (ffloor (+ 2 (/ len 2))))) + (expt 20 (- (floor (+ 2 (/ len 2))))) (/ (expt 20 -3) (expt 5 (- len 10))))) (defun olc-parse-code (code) @@ -254,12 +247,19 @@ invalid." (not (olc-parse-short (olc-parse-code code))) (olc-parse-error nil))) +(defun olc-code-precision (code) + "Return the precision of CODE." + (condition-case nil + (olc-parse-precision (olc-parse-code code)) + (olc-parse-error nil))) + (defun olc-decode (code) "Decode open location code CODE. -Returns a olc-parse structure or raises olc-parse-error if -the code is invalid or olc-decode-error if it cannot (legally) be -decoded. +Returns an `olc-area' structure. Raises `olc-parse-error' if the +code can't be parsed, and `olc-decode-error' if it can't be +decoded (e.g. a padded shortened code, a padded code with grid +coordinates, an empty code, and so forth). Since this function uses floating point calculations, the results are not identical to e.g. the C++ reference implementation. The @@ -296,13 +296,17 @@ differences, however, are extremely small." (defun olc-encode (lat lon len) "Encode LAT and LON as a LEN length open location code. +The length is automatically clipped to between 2 and +15. `olc-encode-error' is raised if the length is otherwise +invalid (i.e. 3, 5, 7, or 9). + Returns an olc-area structure. Raises olc-encode-error if the values cannot (legally) be encoded to the selected length." (setq len (max 2 (min 15 len))) (when (and (< len 11) (/= (% len 2) 0)) (signal 'olc-encode-error "invalid encoding length")) - (setq lat (olc-normalize-latitude lat length) + (setq lat (olc-normalize-latitude lat len) lon (olc-normalize-longitude lon)) (let ((code nil) @@ -343,13 +347,15 @@ values cannot (legally) be encoded to the selected length." (defun olc-recover (code lat lon &optional format) "Recover shortened code CODE from coordinates LAT and LON. -Optional FORMAT specifies the result format. 'latlon means return -the center latitude and longitude as a pair. 'area (the default) -means return an olc-area." +Recovers the closest point to coordinates LAT and LON with a code +that can be shortened to CODE. If FORMAT is `latlon', then the +center of the recovered area (LATITUDE . LONGITUDE) is returned. +If FORMAT is `area' (or any other value), the returned value is an +full open location code." (let ((parse (olc-parse-code code))) (if (olc-is-full parse) (upcase code) - (setq lat (olc-normalize-latitude lat length) + (setq lat (olc-clip-latitude lat) lon (olc-normalize-longitude lon)) (let* ((padlen (- (olc-parse-precision parse) (* 2 (length (olc-parse-pairs parse))) @@ -373,18 +379,49 @@ means return an olc-area." (t (olc-encode lat lon (olc-parse-precision parse)))))))) +(defun olc-shorten (code lat lon &optional limit) + "Attempt to shorten CODE with reference LAT and LON. + +Shorten CODE, which must be a full open location code, using +latitude LAT and longitude LON as the reference. If LIMIT is +specified, then the code will be shortened by at most that many +digits. If the code can't be shortened, the original code is +returned. `olc-shorten-error' is raised if CODE is a padded or +shortened code, of if LIMIT is not positive and even." + (let* ((parse (olc-parse-code code)) + (area (olc-decode parse))) + (when (null limit) (setq limit 12)) + (unless (and (> limit 0) (= 0 (% limit 2))) + (signal 'olc-shorten-error (list "limit must be even and positive" code))) + (when (olc-is-short parse) + (signal 'olc-shorten-error (list "can't shorten shortened codes" code))) + (when (< (olc-parse-precision parse) 8) + (signal 'olc-shorten-error (list "can't shorten padded codes" code))) + + (setq lat (olc-clip-latitude lat) + lon (olc-normalize-longitude lon)) + + (let ((coderange (max (abs (- (olc-area-lat area) lat)) + (abs (- (olc-area-lon area) lon))))) + (catch 'break + (dolist (spec '((4 . 0.0025) (3 . 0.05) (2 . 1) (1 . 20))) + (when (< coderange (* (cdr spec) 0.3)) + (throw 'break (substring code (min limit (* (car spec) 2)))))) + code)))) + (defun olc-recover-string (string &optional reference format) "Recover a location from a shortened open location code and reference. -When called with one string argument, the string is assumed to -contain the code followed by whitespace, and then a reference -location as text. +When called with one argument, it must be a string consisting of a +shortened open location code followed by whitespace and a geographical +location. -When called with two string arguments, the first is assumed to be -the short code and the second is the reference location as text. +When called with two strings, the first must be a shortened open +location code and the second if the geographical location. -A symbol may be included as the last argument to select the -result format. See olc-recover for details." +Optionally, the last argument in either case can be a symbol +indicating the format of the return value (see `olc-recover' for +details)." (unless (fboundp 'request) (error "request library is not loaded")) (let (code resp) diff --git a/olc.texi b/olc.texi new file mode 100644 index 0000000..e8627d7 --- /dev/null +++ b/olc.texi @@ -0,0 +1,248 @@ +\input texinfo +@documentencoding utf-8 +@setfilename olc +@settitle Open Location Code for emacs + +@titlepage +@title Open Location Code for emacs +@author David Byers +@end titlepage + +@node Top +@unnumbered Introduction + +Open Location Code is a way to encode locations in a format that is +easier for people (not computers) to use than latitude and longitude. + +For example, the code 9FCQ9HXG+4C refers to the location 58°23'52.1"N +15°34'33.8"E (58.397813, 15.576063). + +Codes can be shortened by removing characters from the beginning +andding a reference location: 9HXG+4C with the reference "Linköping" +would refer to the same set of coordinates. + +For details about open location code and implementations in other +languages, see https://github.com/google/open-location-code. + +@menu +* Data types:: Data types defined by olc. +* Functions:: Functions defined by olc. +* Index:: Type and function index. +@end menu + +@node Data types,Functions,,Top +@unnumbered Data types + +olc defines two data types: olc-area and olc-parse. The former +represents the result of decoding a code and the latter is the result +of parsing a code, and is mostly for internal use. + +@menu +* olc-area:: The olc-area data type. +* olc-parse:: The olc-parse data type. +@end menu + +@node olc-area,olc-parse,,Data types +@unnumberedsec olc-area + +An olc-area is the area represented by an open location code. All fields +are read-only once the object has been created. + +@defun olc-area-create &key latlo lonlo lathi lonhi +Creates an olc-area with southwest corner (@var{latlo},@var{lonlo}) and +northeast corner (@var{lathi},@var{lonhi}). +@end defun + +@defun olc-area-p obj +Return non-@code{nil} if @var{obj} is an olc-area. +@end defun + +@defun olc-area-latlo area +Return the southern latitude of @var{area}. +@end defun + +@defun olc-area-lonlo area +Return the eastern longitude of @var{area}. +@end defun + +@defun olc-area-lathi area +Return the northern latitude of @var{area}. +@end defun + +@defun olc-area-lonhi area +Return the western longitude of @var{area}. +@end defun + +@defun olc-area-lat area +Return the latitude of the center of @var{area}. +@end defun + +@defun olc-area-lon area +Return the longitude of the center of @var{area}. +@end defun + + +@node olc-parse,,olc-area,Data types +@unnumberedsec olc-parse + +The olc-parse is a structure mainly used internally. Unless you call +@code{olc-parse-code} you will probably never see one. + +@defun olc-parse-create &key pairs grid short prec code +Create an olc-parse structure. Don't call this: use +@code{olc-parse-code} instead. +@end defun + +@defun olc-parse-pairs parse +Returns the list of parsed pairs in @var{parse}. Pairs are first ten +digits of a full code (five pairs). For padded and shortened codes, +the list of pairs could be shorter. +@end defun + +@defun olc-parse-grid parse +Returns the list of parsed grid digits in @var{parse}. Grid digits are +all (up to five) the digits that follow the last pair. +@end defun + +@defun olc-parse-short parse +Return non-@code{nil} if @var{parse} represents a shortened code. +@end defun + +@defun olc-parse-precision parse +Return the precision in digits of the parsed code in @var{parse}. A +full code without padding will have precision 8, 10, or more. Full +codes with padding have precision 6 or lower. Shortened codes should +have at least a precision of 8 since padded codes can't be shortened, +but don't count on this. +@end defun + + +@node Functions,,Data types,Top +@unnumberedsec Functions + +@defun olc-encode lat lon len +Encode a latitude @var{lat}, longitude @var{lon}, into an open +location code of length @var{len}. The length is automatically clipped +to between 2 and 15. (@code{olc-encode-error} is raised if the length +is otherwise invalid (i.e. 3, 5, 7, or 9). + +@example +@group +(olc-encode 58.397813 15.576063 11) +@result{} "9FCQ9HXG+4CG" +(olc-encode 58.397813 15.576063 8) +@result{} "9FCQ9HXG+" +(olc-encode 58.397813 15.576063 4) +@result{} "9FCQ0000+" +@end group +@end example +@end defun + +@defun olc-decode code +Decode @var{code} and return an @code{olc-area} representing the +location. Raises @code{olc-parse-error} if the code can't be parsed, +and @code{olc-decode-error} if it can't be decoded (e.g. a padded +shortened code, a padded code with grid coordinates, an empty code, +and so forth). Returns an olc-area structure. + +@example +@group +(olc-decode "9FCQ9HXG+4CG") +@result{} #s(olc-area 58.397800000000004 15.5760625 58.397825000000005 15.57609375) +(olc-area-lat (olc-decode "9FCQ9HXG+4CG")) +@result{} 58.3978125 +(olc-area-lon (olc-decode "9FCQ9HXG+4CG")) +@result{} 15.576078125 +@end group +@end example +@end defun + +@defun olc-shorten code lat lon &optional limit +Shorten @var{code}, which must be a full open location code, using +latitude @var{lat} and longitude @var{lon} as the reference. If +@var{limit} is specified, then the code will be shortened by at most +that many digits. If the code can't be shortened, the original code is +returned. @code{olc-shorten-error} is raised if @var{code} is a padded +or shortened code, of if @var{limit} is not even. + +@example +@group +(olc-shorten "9C3W9QCJ+2VX" 51.3701125 -1.217765625) +@result{} "+2VX" +(olc-shorten "9C3W9QCJ+2VX" 51.3701125 -1.217765625 4) +@result{} "9QCJ+2VX" +@end group +@end example +@end defun + +@defun olc-recover code lat lon &optional format +Recover the closest point to coordinates @var{lat} and @var{lon} with +a code that can be shortened to @var{code}. If @var{format} is +@code{latlon}, then the center of the recovered area (@var{latitude} . +@var{longitude}) is returned. If @var{format} is @code{area} (or any other +value), the returned value is an full open location code. + +@example +@group +(olc-recover "+2VX" 51.3701125 -1.217765625) +@result{} "9C3W9QCJ+2VX" +(olc-recover "+2VX" 51.3701125 -1.217765625 'latlon) +@result{} (51.370112500000005 . -1.2177656250000002) +@end group +@end example +@end defun + +@defun olc-recover-string arg1 &optional arg2 arg3 +Recover a shortened code @i{without} the reference latitude and +longitude. + +When called with one argument, it must be a string consisting of a +shortened open location code followed by whitespace and a geographical +location. + +When called with two strings, the first must be a shortened open +location code and the second if the geographical location. + +Optionally, the last argument in either case can be a symbol +indicating the format of the return value (see @code{olc-recover} for +details). + +@example +@group +(olc-recover-string "M24Q+89 Mutitjulu") +@result{} "5Q6HM24Q+89" +(olc-recover-string "M24Q+89" "Mutitjulu") +@result{} "5Q6HM24Q+89" +(olc-recover-string "M24Q+89" "Mutitjulu" 'latlon) +@result{} (-25.344187500000004 . 131.0384375) +@end group +@end example + +This function requires the @code{request} package to be installed, and +uses the OpenStreetMap API to convert the geographical reference to +coordinates. Please make sure you follow the acceptable use policy for +the API (e.g., one request per second, tops, allowed). +@end defun + +@defun olc-is-valid code +Returns non-@code{nil} if @var{code} is a valid open location code. +@end defun + +@defun olc-is-short code +Returns non-@code{nil} if @var{code} is a valid short location code. +Returns @code{nil} for valid short and for invalid codes. +@end defun + +@defun olc-is-full code +Returns non-@code{nil} if @var{code} is a valid full open location +code. Returns @code{nil} for valid long and for invalid codes. +@end defun + + +@node Index,,Functions,Top +@unnumbered Index + +@printindex tp +@printindex fn + +@bye diff --git a/test/olctest.el b/test/olctest.el index bdc9f18..bf2af42 100644 --- a/test/olctest.el +++ b/test/olctest.el @@ -64,15 +64,26 @@ (kill-buffer buffer)))) -(defmacro olctest-run-tests (spec &rest body) +(defmacro olctest-run-csv (spec &rest body) "Run open location code tests. \(fn (VAR LIST) BODY...)" (declare (indent 1) (debug ((form symbolp) body))) (let ((data (gensym "$olctest"))) - `(let ((,data (olctest-read-csv ,(elt spec 0))) - ($olctest-results nil)) - (setq foo ,data) + `(let* ((,data (olctest-read-csv ,(elt spec 0))) + ($olctest-results nil)) + (dolist (,(elt spec 1) ,data) + ,@body) + (olctest-report-results $olctest-results)))) + +(defmacro olctest-run-list (spec &rest body) + "Run open location code tests. + +\(fn (VAR LIST) BODY...)" + (declare (indent 1) (debug ((form symbolp) body))) + (let ((data (gensym "$olctest"))) + `(let* ((,data ,(elt spec 0)) + ($olctest-results nil)) (dolist (,(elt spec 1) ,data) ,@body) (olctest-report-results $olctest-results)))) @@ -97,7 +108,7 @@ (defun olctest-encode () "Test encoding." - (olctest-run-tests ("encoding.csv" case) + (olctest-run-csv ("encoding.csv" case) (let ((code (olc-encode (alist-get 'latitude case) (alist-get 'longitude case) (alist-get 'length case)))) @@ -107,14 +118,14 @@ (defun olctest-decode () "Test decoding." - (olctest-run-tests ("decoding.csv" case) + (olctest-run-csv ("decoding.csv" case) (let ((area (olc-decode (alist-get 'code case))) (exp-latlo (alist-get 'latLo case)) (exp-lathi (alist-get 'latHi case)) (exp-lonlo (alist-get 'lngLo case)) (exp-lonhi (alist-get 'lngHi case)) (exp-len (alist-get 'length case))) - (unless (and (= exp-len (olc-code-length (alist-get 'code case))) + (unless (and (= exp-len (olc-code-precision (alist-get 'code case))) (< (abs (- (olc-area-latlo area) exp-latlo)) olctest-decode-tolerance) (< (abs (- (olc-area-lathi area) exp-lathi)) olctest-decode-tolerance) (< (abs (- (olc-area-lonlo area) exp-lonlo)) olctest-decode-tolerance) @@ -122,7 +133,7 @@ (olctest-record-failure case (format "%d,%f,%f,%f,%f" exp-len exp-latlo exp-lonlo exp-lathi exp-lonhi) (format "%d,%f,%f,%f,%f" - (olc-code-length (alist-get 'code case)) + (olc-code-precision (alist-get 'code case)) (olc-area-latlo area) (olc-area-lonlo area) (olc-area-lathi area) @@ -131,7 +142,7 @@ (defun olctest-shortcodes () "Test recovering." - (olctest-run-tests ("shortCodeTests.csv" case) + (olctest-run-csv ("shortCodeTests.csv" case) (let ((fullcode (alist-get 'fullcode case)) (lat (alist-get 'lat case)) (lon (alist-get 'lng case)) @@ -146,13 +157,15 @@ ;; Test shorten (when (or (string= test-type "B") (string= test-type "S")) - ;; Shorten is not implemented - ) + (let ((shortened (olc-shorten fullcode lat lon))) + (unless (string= shortened shortcode) + (olctest-record-failure case shortcode shortened)))) ))) + (defun olctest-validity () "Test validity." - (olctest-run-tests ("validityTests.csv" case) + (olctest-run-csv ("validityTests.csv" case) (let* ((code (alist-get 'code case)) (expected (list (alist-get 'isValid case) (alist-get 'isShort case) @@ -163,12 +176,29 @@ (unless (equal expected actual) (olctest-record-failure case expected actual))))) +(defvar olctest-local-shorten-tests + '(((code . "9C3W9QCJ+2VX") (lat . 51.3701125) (lon . -1.217765625) (len . 8) (exp . "+2VX")) + ((code . "9C3W9QCJ+2VX") (lat . 51.3701125) (lon . -1.217765625) (len . 6) (exp . "CJ+2VX")) + ((code . "9C3W9QCJ+2VX") (lat . 51.3701125) (lon . -1.217765625) (len . 4) (exp . "9QCJ+2VX")) + ((code . "9C3W9QCJ+2VX") (lat . 51.3701125) (lon . -1.217765625) (len . 2) (exp . "3W9QCJ+2VX")))) + +(defun olctest-localtests () + (olctest-run-list (olctest-local-shorten-tests case) + (let* ((fullcode (alist-get 'code case)) + (lat (alist-get 'lat case)) + (lon (alist-get 'lon case)) + (len (alist-get 'len case)) + (shortcode (alist-get 'exp case)) + (actual (olc-shorten fullcode lat lon len))) + (unless (string= actual shortcode) + (olctest-record-failure case shortcode actual))))) + (defun olctest-run-all () "Run all tests." (and (olctest-decode) (olctest-encode) (olctest-shortcodes) - (olctest-validity))) - - + (olctest-validity) + (olctest-localtests) + )) -- GitLab