Perl, строки, числа с плавающей запятой, модульное тестирование и регулярные выражения! - PullRequest
5 голосов
/ 10 февраля 2011

ОК, в качестве предисловия этот вопрос потенциально «глупее» моего обычного уровня вопроса - однако эта проблема меня раздражала в последние несколько дней, поэтому я все равно задам ее.Я приведу ложный пример того, в чем заключается моя проблема, так что я могу надеяться обобщить ее для моей текущей проблемы.

#!/usr/bin/perl -w use strict;

use Test::More 'no_plan';

my $fruit_string = 'Apples cost $1.50';
my ($fruit, $price) = $fruit_string =~ /(\w+)s cost \$(\d+\.\d+)/;

# $price += 0; # Uncomment for Great Success
is ($price, 1.50, 'Great Success');

Теперь, когда это выполняется, я получаю сообщение

#   Failed test 'Great Success'
#          got: '1.50'
#     expected: '1.5'

Чтобы тест работал, я либо раскомментирую закомментированную строку, либо использую is ($price, '1.50', 'Great Success').Оба варианта не работают для меня - я тестирую огромное количество вложенных данных, используя Test :: Deep и cmp_deeply.Мой вопрос заключается в том, как вы можете извлечь двойное число из регулярного выражения, а затем сразу использовать его как двойное - или, если есть лучший способ, дайте мне знать - и не стесняйтесь говорить мне заняться садоводством или что-то в этом роде.трудно.

Ответы [ 5 ]

10 голосов
/ 10 февраля 2011

Вы уже используете Test :: Deep, , поэтому вы можете просто использовать оболочку num() для выполнения числового, а не строкового сравнения (оно даже позволяет добавить допуск для сравнения двух неточные значения с плавающей точкой):

cmp_deeply(
    $result,
    {
        foo         => 'foo',
        bar         => 'blah',
        quantity    => 3,
        price       => num(1.5),
    },
    'result hash is correct',
);

Для обычных сравнений, выполняемых отдельно, cmp_ok будет работать, но num() все еще доступно: cmp_deeply($value, num(1.5), 'test name') все еще работает.

1 голос
/ 10 февраля 2011

Ваши тесты не пройдены, потому что is($x, $y, $name) эквивалентно cmp_ok($x, 'eq', $y, $name). eq заставляет каждый из его аргументов оцениваться как строки. Поскольку вам нужно числовое равенство, вы можете записать его с помощью cmp_ok, используя '=='. Вы могли бы упростить задачу, написав собственную числовую версию is:

sub is_num {cmp_ok $_[0], '==', $_[1], $_[2]}

Но эта версия слегка нарушена, она будет сообщать об ошибках в неправильных строках. Чтобы в отчете об ошибках отображались правильные строки:

sub is_num {splice @_, 1, 0, '=='; goto &cmp_ok}

Причина goto &sub заключается в том, что cmp_ok использует caller, чтобы определить, где произошла ошибка. Синтаксис goto &sub стирает настройку кадра вызова для is_num, так что cmp_ok считает, что он вызывается из местоположения, в котором был is_num.

Наконец, заглушка моего модуля Test :: Magic , которая обеспечивает синтаксический сахар для Test::More:

use Test::Magic 'no_plan';

... # setup code

test 'fruit price',
  is $price == 1.50;

Что интерпретируется как cmp_ok( $price, '==', 1.50, 'fruit price')

1 голос
/ 10 февраля 2011

Почему бы не использовать проверенный ok?Вы будете тестировать то, что действительно хотите проверить, и вам не придется беспокоиться о том, что is делает что-то слишком тонкое или слишком умное.

ok($price == 1.5, 'Great Success');

is действительно обеспечивает некоторую дополнительную диагностикув случае неудачи, но это достаточно просто сделать с ok, также

ok($price == 1.5, 'Great Success') or diag("Expected \$price==1.5, got $price");
1 голос
/ 10 февраля 2011

Force $price интерпретируется как число:

is ( 0 + $price, 1.50, 'Great Success');
0 голосов
/ 10 февраля 2011

Причиной такого поведения является то, что для сравнения используется eq, что приводит к строковой классификации его аргументов.1.50 преобразуется в '1.5', и это не получается.

Вы должны жить с поведением (принудительное приведение в соответствие или нумерация) или написать свой собственный вариант, который будет сравниваться численно, если обе стороны выглядят как числапрежде чем вернуться к эквалайзерам.Я бы лично пошел с последним подходом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...