1
\$\begingroup\$

I have some code where the purpose is the decide if a char is between quotes in an expression. For example, awk '{print 1ドル}' has a { between quotes.

The function that I want to test is

int IBQplain(int pos, char *str, int offset);
int IBQdouble(int pos, char *str, int offset);
int IBQsingle(int pos, char *str, int offset) {
 int escaped = 0;
 for (; str[offset]; ++offset) {
 if (!escaped) {
 switch (str[offset]) {
 case '\\':
 escaped = 1;
 case '\'':
 return IBQplain(pos, str, offset + 1);
 }
 } else {
 escaped = 0;
 }
 if (pos == offset) {
 return 1;
 }
 }
 return 0;
}
int IBQdouble(int pos, char *str, int offset) {
 char ch;
 if (pos == offset)
 return 0; /* Not within quotes */
 int escaped = 0;
 for (ch = str[offset]; ch; ch = str[++offset]) {
 if (!escaped) {
 switch (str[offset]) {
 case '\'':
 return IBQsingle(pos, str, offset + 1);
 case '"':
 return IBQdouble(pos, str, offset + 1);
 case '\\':
 escaped = 1;
 }
 } else {
 escaped = 0;
 }
 if (pos == offset)
 return escaped; /* Not within quotes, but may be single-escaped */
 }
 return 0; /* FIXME */
}
int IBQplain(int pos, char *str, int offset) {
 char ch;
 if (pos == offset)
 return 0; /* Not within quotes */
 int escaped = 0;
 for (ch = str[offset]; ch; ch = str[++offset]) {
 if (!escaped) {
 switch (str[offset]) {
 case '\'':
 return IBQsingle(pos, str, offset + 1);
 case '"':
 return IBQdouble(pos, str, offset + 1);
 case '\\':
 escaped = 1;
 }
 } else {
 escaped = 0;
 }
 if (pos == offset)
 return escaped; /* Not within quotes, but may be single-escaped */
 }
 return 0; /* FIXME */
}
int isBetweenQuotes(int pos, char *str) {
 return IBQplain(pos, str, 0);
}

Write the test

#include "openshell.h"
#include "errors.h"
#test myQtest
fail_unless(isBetweenQuotes(11, "abc'asdqerfdsdxcvc'xc") == 1, "isBetweenQuotes function borked");
lm */

Compile it and run it

gcc -Wall -o bquotes-test util.c errors.c bquotes-test.c -lcheck -lsubunit -lrt -pthread -lm^C
dac@dac-Latitude-E7450:~/osh$ ./bquotes-test 
Running suite(s): Core
100%: Checks: 1, Failures: 0, Errors: 0

It seems ok. I make more tests

#include "openshell.h"
#include "errors.h"
#test myQtest
fail_unless(isBetweenQuotes(11, "abc'asdqerfdsdxcvc'xc") == 1, "isBetweenQuotes function borked");
fail_unless(isBetweenQuotes(5, "abcasdqerfdsdxcvcxc") == 0, "isBetweenQuotes function borked");
fail_unless(isBetweenQuotes(11, "ab'c'as'dqerfdsdxcvc'xc") == 1, "isBetweenQuotes function borked");

Compile and run it

checkmk tst_bquotes.check > bquotes-test.c
dac@dac-Latitude-E7450:~/osh$ gcc -Wall -o bquotes-test util.c errors.c bquotes-test.c -lcheck -lsubunit -lrt -pthread -lm
dac@dac-Latitude-E7450:~/osh$ ./bquotes-test 
Running suite(s): Core
100%: Checks: 1, Failures: 0, Errors: 0
asked Jun 2, 2016 at 17:29
\$\endgroup\$
4
  • \$\begingroup\$ What's the purpose of your code? What problem does it solve? \$\endgroup\$ Commented Jun 2, 2016 at 17:54
  • \$\begingroup\$ @Mast I added the purpose of the code: I have some code where the purpose is the decide if a char is between quotes in an expression. For example, awk '{print 1ドル}' has a { between quotes. \$\endgroup\$ Commented Jun 2, 2016 at 18:21
  • \$\begingroup\$ Ah, that explains a lot. \$\endgroup\$ Commented Jun 2, 2016 at 18:23
  • \$\begingroup\$ @Mast Yes it solves a rather important problem for me...I must check if certain char are between quotes to be able to parse commands properly. Now I'm learning to write my first unit tests with check. \$\endgroup\$ Commented Jun 2, 2016 at 18:25

1 Answer 1

2
\$\begingroup\$

As OP did not explicitly state the review goals, here are some general ideas.

  1. Use const when referenced data is not changed. Allows for optimizations and defined behavior when the array address passed is const.

    // int IBQplain(int pos, char *str, int offset);
    // int IBQdouble(int pos, char *str, int offset);
    // int IBQsingle(int pos, char *str, int offset);
    int IBQplain(int pos, const char *str, int offset);
    int IBQdouble(int pos, const char *str, int offset);
    int IBQsingle(int pos, const char *str, int offset);
    
  2. Use size_t as the type for array indexes. int maybe insufficient.

    // int IBQplain(int pos, char *str, int offset);
    int IBQplain(size_t pos, char *str, size_t offset);
    
  3. As the functions only return 1 of 2 values, consider _Bool or bool

    #include <stdbool.h>
    // int IBQplain(size_t pos, char *str, size_t offset);
    bool IBQplain(size_t pos, char *str, size_t offset);
    
  4. As these functions appear to be stand-alone, suggest more pessimistic range checking:

    // if (pos == offset)
    if (pos <= offset)
     return 0; /* Not within quotes */
    
  5. ... otherwise if the below 3 are only helper functions to isBetweenQuotes(), they should be static.

    static int IBQplain(int pos, const char *str, int offset);
    static int IBQdouble(int pos, const char *str, int offset);
    static int IBQsingle(int pos, const char *str, int offset);
    
  6. Unclear why code accesses the array again instead of ch

    for (ch = str[offset]; ch; ch = str[++offset]) {
     if (!escaped) {
     // switch (str[offset]) {
     switch (ch) {
    
  7. Expect more test cases that have incomplete '' and "" pair combinations, especially onces that begin or end the string.

answered Jun 2, 2016 at 22:06
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.