Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
alyyousuf7 committed Sep 17, 2020
0 parents commit b7758a3
Show file tree
Hide file tree
Showing 12 changed files with 447 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
cli/imei/imei
21 changes: 21 additions & 0 deletions LICENSE
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 Ali Yousuf

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
13 changes: 13 additions & 0 deletions Makefile
@@ -0,0 +1,13 @@
.PHONY: build
build: test imei

.PHONY: test
test: *.go
go test ./...

.PHONY: clean
clean:
rm imei

imei: *.go cli/imei/*.go
go build ./cli/imei/...
20 changes: 20 additions & 0 deletions README.md
@@ -0,0 +1,20 @@
# IMEI converter
This tool takes an IMEI in one format and outputs in another.

## Supported IMEI formats
- 18 digit decimal
- 14 digit hexadecimal
- 15 digit hexadecimal with checksum

## Build
```sh
$ make build
$ ./imei -h
Usage of ./imei:
-input path
input path (use - for stdin) (default "-")
-input-format format
input imei format [auto, hex-checksum, hex, dec] (default "auto")
-output-format format
output imei format [hex-checksum, hex, dec] (default "hex-checksum")
```
25 changes: 25 additions & 0 deletions checksum.go
@@ -0,0 +1,25 @@
package imei

import (
"strconv"
"strings"
)

func ChecksumFromString(str string) int {
sum := 0
for i, ch := range strings.Split(str, "") {
n, _ := strconv.Atoi(ch)

if (i % 2) == 1 {
n = n * 2
}

if n >= 10 {
n = (n % 10) + 1
}

sum = sum + n
}

return (10 - (sum % 10)) % 10
}
27 changes: 27 additions & 0 deletions checksum_test.go
@@ -0,0 +1,27 @@
package imei_test

import (
"testing"

"github.com/alyyousuf7/imei-go"
)

func TestGenerateChecksum(t *testing.T) {
testcases := []struct {
str string
checksum int
}{
{"00000000000000", 0},
{"35464110052131", 2},
{"35611709842290", 2},
{"35862909296647", 6},
{"35671608638324", 8},
}

for _, testcase := range testcases {
checksum := imei.ChecksumFromString(testcase.str)
if checksum != testcase.checksum {
t.Errorf("Expected checksum %d for %s, but got %d", testcase.checksum, testcase.str, checksum)
}
}
}
105 changes: 105 additions & 0 deletions cli/imei/main.go
@@ -0,0 +1,105 @@
package main

import (
"bufio"
"flag"
"fmt"
"io"
"os"
"strings"

"github.com/alyyousuf7/imei-go"
)

func main() {
// Flags
allowedInputFormats := []string{"auto", "hex-checksum", "hex", "dec"}
allowedOutputFormats := []string{"hex-checksum", "hex", "dec"}

var inputFormat string
flag.StringVar(&inputFormat, "input-format", allowedInputFormats[0], fmt.Sprintf("input imei `format` [%s]", strings.Join(allowedInputFormats, ", ")))

var outputFormat string
flag.StringVar(&outputFormat, "output-format", allowedOutputFormats[0], fmt.Sprintf("output imei `format` [%s]", strings.Join(allowedOutputFormats, ", ")))

var inputFile string
flag.StringVar(&inputFile, "input", "-", "input `path` (use - for stdin)")

flag.Parse()

var outputIMEIType imei.IMEIType
switch outputFormat {
case "dec":
outputIMEIType = imei.DecimalIMEI
case "hex":
outputIMEIType = imei.HexadecimalIMEI
case "hex-checksum":
outputIMEIType = imei.HexadecimalChecksumIMEI
default:
fmt.Println("Usage:")
flag.PrintDefaults()
os.Exit(1)
}

// Read
var file io.Reader

if inputFile == "-" {
file = os.Stdin
} else {
file, err := os.Open(inputFile)
if err != nil {
fmt.Println(err)
fmt.Println()

fmt.Println("Usage:")
flag.PrintDefaults()
os.Exit(1)
}
defer file.Close()
}

scanner := bufio.NewScanner(file)
for scanner.Scan() {
text := scanner.Text()

var parsedIMEI *imei.IMEI
var err error

switch inputFormat {
case "auto":
parsedIMEI, err = imei.DecimalIMEI.Parse(text)
if err != nil {
parsedIMEI, err = imei.HexadecimalIMEI.Parse(text)
if err != nil {
parsedIMEI, err = imei.HexadecimalChecksumIMEI.Parse(text)
}
}
case "dec":
parsedIMEI, err = imei.DecimalIMEI.Parse(text)
case "hex":
parsedIMEI, err = imei.HexadecimalIMEI.Parse(text)
case "hex-checksum":
parsedIMEI, err = imei.HexadecimalChecksumIMEI.Parse(text)
default:
fmt.Println("unknown input format")
fmt.Println()

fmt.Println("Usage:")
flag.PrintDefaults()
os.Exit(1)
break
}

if err != nil {
fmt.Println(text, "-", err)
} else if parsedIMEI != nil {
fmt.Println(parsedIMEI.String(outputIMEIType))
}
}

if err := scanner.Err(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
96 changes: 96 additions & 0 deletions conversion_test.go
@@ -0,0 +1,96 @@
package imei_test

import (
"testing"

"github.com/alyyousuf7/imei-go"
)

func TestToDecimalIMEI(t *testing.T) {
shouldPassCases := []string{"000000000000000000", "999999999999999999", "012345678901234567"}
for _, str := range shouldPassCases {
outIMEI, err := imei.DecimalIMEI.Parse(str)
if err != nil {
t.Errorf("Failed on parse %s: %s", str, err)
continue
}

result := outIMEI.String(imei.DecimalIMEI)
if result != str {
t.Errorf("Expected %s, but got %s", str, result)
}
}
}

func TestToHexadecimalIMEI(t *testing.T) {
shouldPassCases := []string{"00000000000000", "99999999999999"}
for _, str := range shouldPassCases {
outIMEI, err := imei.HexadecimalIMEI.Parse(str)
if err != nil {
t.Errorf("Failed on parse %s: %s", str, err)
continue
}

result := outIMEI.String(imei.HexadecimalIMEI)
if result != str {
t.Errorf("Expected %s, but got %s", str, result)
}
}
}

func TestIMEICrossConversion(t *testing.T) {
conversionTestCase := []struct {
Decimal string
Hexadecimal string
Checksum string
}{
{"030541989609441844", "12345678901234", "7"},
{"089379662400336177", "35464110052131", "2"},
{"089555533708659600", "35611709842290", "2"},
{"089798477702713159", "35862909296647", "6"},
{"089594829606521636", "35671608638324", "8"},
}

for _, testcase := range conversionTestCase {
// Decimal to Hexadecimal
i, err := imei.DecimalIMEI.Parse(testcase.Decimal)
if err != nil {
t.Errorf("Failed on parse %s: %s", testcase.Decimal, err)
continue
}

hex := i.String(imei.HexadecimalIMEI)
if hex != testcase.Hexadecimal {
t.Errorf("Expected Hexadecimal %s, but got %s", testcase.Hexadecimal, hex)
}

hex = i.String(imei.HexadecimalChecksumIMEI)
if hex != testcase.Hexadecimal+testcase.Checksum {
t.Errorf("Expected Hexadecimal with checksum %s, but got %s", testcase.Hexadecimal+testcase.Checksum, hex)
}

// Hexadecimal to Decimal
i, err = imei.HexadecimalIMEI.Parse(testcase.Hexadecimal)
if err != nil {
t.Errorf("Failed on parse %s: %s", testcase.Hexadecimal, err)
continue
}

dec := i.String(imei.DecimalIMEI)
if dec != testcase.Decimal {
t.Errorf("Expected Decimal %s, but got %s", testcase.Decimal, dec)
}

// Hexadecimal (Checksum) to Decimal
i, err = imei.HexadecimalChecksumIMEI.Parse(testcase.Hexadecimal + testcase.Checksum)
if err != nil {
t.Errorf("Failed on parse %s: %s", testcase.Hexadecimal+testcase.Checksum, err)
continue
}

dec = i.String(imei.DecimalIMEI)
if dec != testcase.Decimal {
t.Errorf("Expected Decimal %s, but got %s", testcase.Decimal, dec)
}
}
}
3 changes: 3 additions & 0 deletions go.mod
@@ -0,0 +1,3 @@
module github.com/alyyousuf7/imei-go

go 1.15
Binary file added imei
Binary file not shown.

0 comments on commit b7758a3

Please sign in to comment.