Skip to content
This repository has been archived by the owner on Sep 3, 2021. It is now read-only.

Commit

Permalink
fix: allow CIDs to be compared through deep equality
Browse files Browse the repository at this point in the history
The changes in #131 broke the tests of IPFS and probably quite a few
other modules.

This sort of thing used to work, now does not:

```js
expect(ipfs.bitswap.unwant.calledWith(new CID(cidStr), defaultOptions)).to.be.true()
```

The reason it breaks is because internally `calledWith` does a `deepEqual`
on the args which compares (among other things) the properties of the passed
objects.

We used to use `Object.defineProperty` to create cached versions of
expensive to calculate fields which makes fields non-enumerable by
default so they are skipped during the `deepEqual` check.

Now we just set the fields on the object which means instances have
different fields depending on which constructor branch was hit or worse,
if the instances properties have been accessed.
  • Loading branch information
achingbrain authored and vmx committed Dec 11, 2020
1 parent 26c436d commit 127745e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"uint8arrays": "^1.1.0"
},
"devDependencies": {
"@sinonjs/samsam": "^5.3.0",
"aegir": "^29.0.1",
"multihashing-async": "^2.0.1"
},
Expand Down
9 changes: 6 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class CID {
this.multibaseName = 'base58btc'
}
CID.validateCID(this)
this.string = version
Object.defineProperty(this, 'string', { value: version })
return
}

Expand Down Expand Up @@ -164,6 +164,7 @@ class CID {
*
*/
get bytes () {
// @ts-ignore
let bytes = this._bytes

if (!bytes) {
Expand All @@ -179,7 +180,7 @@ class CID {
}

// Cache this Uint8Array so it doesn't have to be recreated
this._bytes = bytes
Object.defineProperty(this, '_bytes', { value: bytes })
}

return bytes
Expand Down Expand Up @@ -248,7 +249,9 @@ class CID {
* @returns {string}
*/
toBaseEncodedString (base = this.multibaseName) {
// @ts-ignore non enumerable cache property
if (this.string && this.string.length !== 0 && base === this.multibaseName) {
// @ts-ignore non enumerable cache property
return this.string
}
let str
Expand All @@ -264,7 +267,7 @@ class CID {
}
if (base === this.multibaseName) {
// cache the string value
this.string = str
Object.defineProperty(this, 'string', { value: str })
}
return str
}
Expand Down
44 changes: 44 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const multihashing = require('multihashing-async')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string')
const CID = require('../src')
const { deepEqual } = require('@sinonjs/samsam')

describe('CID', () => {
let hash
Expand Down Expand Up @@ -448,4 +449,47 @@ describe('CID', () => {
expect(cid.toBaseEncodedString()).to.equal(base32String)
})
})

describe('equality', () => {
it('should be deeply equal', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')

expect(deepEqual(cid1, cid2)).to.be.true()
})

it('should be deeply equal when constructed from another CID', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1)

expect(deepEqual(cid1, cid2)).to.be.true()
})

it('should be deeply equal when constructed from an Uint8Array', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1.multihash)

expect(deepEqual(cid1, cid2)).to.be.true()
})

it('should still be deeply equal after turning one into a base encoded string', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1.multihash)
const cid3 = new CID(cid1.multihash)

cid3.toBaseEncodedString()

expect(deepEqual(cid2, cid3)).to.be.true()
})

it('should still be deeply equal after turning one into bytes', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1.multihash)
const cid3 = new CID(cid1.multihash)

cid3.bytes // eslint-disable-line no-unused-expressions

expect(deepEqual(cid2, cid3)).to.be.true()
})
})
})

0 comments on commit 127745e

Please sign in to comment.